static int eb_canjoin(const char *data, struct Client *client_p, struct Channel *chptr, long mode_type) { struct Channel *chptr2; int ret; static int recurse = 0; (void)mode_type; /* don't process a $j in a $j'ed list */ if (recurse) return EXTBAN_INVALID; if (data == NULL) return EXTBAN_INVALID; chptr2 = find_channel(data); /* must exist, and no point doing this with the same channel */ if (chptr2 == NULL || chptr2 == chptr) return EXTBAN_INVALID; /* require consistent target */ if (chptr->chname[0] == '#' && data[0] == '&') return EXTBAN_INVALID; /* this allows getting some information about ban exceptions * but +s/+p doesn't seem the right criterion */ #if 0 /* privacy! don't allow +s/+p channels to influence another channel */ if (!PubChannel(chptr2)) return EXTBAN_INVALID; #endif recurse = 1; ret = is_banned(chptr2, client_p, NULL, NULL, NULL) == CHFL_BAN ? EXTBAN_MATCH : EXTBAN_NOMATCH; recurse = 0; return ret; }
static int eb_channel(const char *data, struct Client *client_p, struct Channel *chptr, long mode_type) { struct Channel *chptr2; (void)chptr; (void)mode_type; if (data == NULL) return EXTBAN_INVALID; chptr2 = find_channel(data); if (chptr2 == NULL) return EXTBAN_INVALID; /* privacy! don't allow +s/+p channels to influence another channel */ if (!PubChannel(chptr2)) return EXTBAN_INVALID; return IsMember(client_p, chptr2) ? EXTBAN_MATCH : EXTBAN_NOMATCH; }
static int eb_channel(const char *data, struct Client *client_p, struct Channel *chptr, long mode_type) { struct Channel *chptr2; (void)chptr; (void)mode_type; if (data == NULL) return EXTBAN_INVALID; chptr2 = find_channel(data); if (chptr2 == NULL) return EXTBAN_INVALID; /* require consistent target */ if (chptr->chname[0] == '#' && data[0] == '&') return EXTBAN_INVALID; /* privacy! don't allow +s/+p channels to influence another channel */ if (!PubChannel(chptr2) && chptr2 != chptr) return EXTBAN_INVALID; return IsMember(client_p, chptr2) ? EXTBAN_MATCH : EXTBAN_NOMATCH; }
/* ** m_who ** parv[0] = sender prefix ** parv[1] = nickname mask list ** parv[2] = additional selection flag, only 'o' for now. */ int m_who(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Client *acptr; char *mask = parc > 1 ? parv[1] : NULL; Link *lp; struct Channel *chptr; struct Channel *mychannel = NULL; char *channame = NULL; int oper = parc > 2 ? (*parv[2] == 'o' ): 0; /* Show OPERS only */ int member; int maxmatches = 500; mychannel = NullChn; if (sptr->user) if ((lp = sptr->user->channel)) mychannel = lp->value.chptr; /* ** Following code is some ugly hacking to preserve the ** functions of the old implementation. (Also, people ** will complain when they try to use masks like "12tes*" ** and get people on channel 12 ;) --msa */ if (mask) { if (!strcmp(mask, "**")) mask = NULL; else if (*mask == (char) 0) mask = NULL; else (void)collapse(mask); } if (!mask || (*mask == (char) 0)) { if (!HasUmode(sptr,UMODE_USER_AUSPEX)) { sendto_one(sptr, form_str(RPL_ENDOFWHO), me.name, parv[0], EmptyString(mask) ? "*" : mask); return 0; } } else if ((*(mask+1) == (char) 0) && (*mask == '*')) { if (!mychannel) { sendto_one(sptr, form_str(RPL_ENDOFWHO), me.name, parv[0], EmptyString(mask) ? "*" : mask); return 0; } channame = mychannel->chname; } else channame = mask; if (IsChannelName(channame)) { /* * List all users on a given channel */ if (!oper || SeesOpers(sptr)) /* If you're doing an oper search, you need SeesOpers() */ { chptr = hash_find_channel(channame, NULL); if (chptr) { member = IsMember(sptr, chptr) || IsLogger(sptr, chptr) || HasUmode(sptr,UMODE_USER_AUSPEX); if (member || !SecretChannel(chptr)) for (lp = chptr->members; lp; lp = lp->next) { if (oper && !HasUmode(lp->value.cptr,UMODE_OPER)) continue; if (IsInvisible(lp->value.cptr) && !member) continue; do_who(sptr, lp->value.cptr, chptr, lp); } } } } else if (mask && ((acptr = find_client(mask, NULL)) != NULL) && IsPerson(acptr) && (!oper || (HasUmode(acptr,UMODE_OPER) && SeesOpers(sptr)))) { int isinvis = 0; struct Channel *ch2ptr = NULL; isinvis = IsInvisible(acptr); for (lp = acptr->user->channel; lp; lp = lp->next) { chptr = lp->value.chptr; member = IsMember(sptr, chptr) || HasUmode(sptr,UMODE_USER_AUSPEX); if (isinvis && !member) continue; if (member || (!isinvis && PubChannel(chptr))) { ch2ptr = chptr; break; } } do_who(sptr, acptr, ch2ptr, NULL); } else if (!oper || SeesOpers(sptr)) for (acptr = GlobalClientList; acptr; acptr = acptr->next) { struct Channel *ch2ptr = NULL; int showperson, isinvis; if (!IsPerson(acptr)) continue; if (oper && !HasUmode(acptr,UMODE_OPER)) continue; showperson = 0; /* * Show user if they are on the same channel, or not * invisible and on a non secret channel (if any). * Do this before brute force match on all relevant fields * since these are less cpu intensive (I hope :-) and should * provide better/more shortcuts - avalon */ isinvis = IsInvisible(acptr); for (lp = acptr->user->channel; lp; lp = lp->next) { chptr = lp->value.chptr; member = IsMember(sptr, chptr) || HasUmode(sptr, UMODE_USER_AUSPEX); if (isinvis && !member) continue; if (member || (!isinvis && PubChannel(chptr))) { ch2ptr = chptr; showperson = 1; break; } if (HiddenChannel(chptr) && !SecretChannel(chptr) && !isinvis) showperson = 1; } if (!acptr->user->channel && !isinvis) showperson = 1; if ((HasUmode(sptr,UMODE_USER_AUSPEX) || showperson) && (!mask || match(mask, acptr->name) || match(mask, acptr->username) || match(mask, acptr->host) || (HasUmode(sptr, UMODE_AUSPEX) && match(mask, acptr->user->server)) || match(mask, acptr->info))) { do_who(sptr, acptr, ch2ptr, NULL); if (!HasUmode(sptr,UMODE_USER_AUSPEX) && !--maxmatches) { sendto_one(sptr, form_str(RPL_ENDOFWHO), me.name, parv[0], EmptyString(mask) ? "*" : mask); return 0; } } } sendto_one(sptr, form_str(RPL_ENDOFWHO), me.name, parv[0], EmptyString(mask) ? "*" : mask); return 0; }
int m_names(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel *chptr; struct Channel *ch2ptr; struct Client *c2ptr; struct Membership* member; char* s; char* para = parc > 1 ? parv[1] : 0; int showingdelayed = 0; if (parc > 1 && !ircd_strcmp(parv[1], "-D")) { para = (parc > 2) ? parv[2] : 0; showingdelayed = NAMES_DEL; if (parc > 3 && hunt_server_cmd(sptr, CMD_NAMES, cptr, 1, "%s %s %C", 3, parc, parv)) return 0; } else if (parc > 2 && hunt_server_cmd(sptr, CMD_NAMES, cptr, 1, "%s %C", 2, parc, parv)) return 0; if (EmptyString(para)) { send_reply(sptr, RPL_ENDOFNAMES, "*"); return 0; } do { s = strchr(para, ','); if (s) *s++ = '\0'; /* * Special Case 1: "/names 0". * Full list as per RFC. */ if ((*para == '0') || (*para == '\0')) { int idx; int mlen; int flag; struct Channel *ch3ptr; char buf[BUFSIZE]; mlen = strlen(cli_name(&me)) + 10 + strlen(cli_name(sptr)); /* List all visible channels/visible members */ for (ch2ptr = GlobalChannelList; ch2ptr; ch2ptr = ch2ptr->next) { if (!ShowChannel(sptr, ch2ptr)) continue; /* Don't show secret chans. */ else if (find_channel_member(sptr, ch2ptr)) do_names(sptr, ch2ptr, showingdelayed|NAMES_ALL); /* Full list if we're in this chan. */ else do_names(sptr, ch2ptr, showingdelayed|NAMES_VIS); } /* List all remaining users on channel '*' */ strcpy(buf, "* * :"); idx = 5; flag = 0; for (c2ptr = GlobalClientList; c2ptr; c2ptr = cli_next(c2ptr)) { int showflag = 0; if (!IsUser(c2ptr) || (sptr != c2ptr && IsInvisible(c2ptr))) continue; member = cli_user(c2ptr)->channel; while (member) { ch3ptr = member->channel; if (PubChannel(ch3ptr) || find_channel_member(sptr, ch3ptr)) showflag = 1; member = member->next_channel; } if (showflag) /* Have we already shown them? */ continue; strcpy(buf + idx, cli_name(c2ptr)); idx += strlen(cli_name(c2ptr)); buf[idx++] = ' '; flag = 1; if (mlen + idx + NICKLEN + 3 > BUFSIZE) /* space, \r\n\0 */ { send_reply(sptr, RPL_NAMREPLY, buf); strcpy(buf, "* * :"); idx = 5; flag = 0; } } if (flag) send_reply(sptr, RPL_NAMREPLY, buf); send_reply(sptr, RPL_ENDOFNAMES, "*"); } else if ((chptr = FindChannel(para)) != NULL) { member = find_member_link(chptr, sptr); if (member) { /* * Special Case 2: User is on this channel, requesting full names list. * (As performed with each /join) - ** High frequency usage ** */ do_names(sptr, chptr, showingdelayed|NAMES_ALL|NAMES_EON); } else { /* * Special Case 3: User isn't on this channel, show all visible users, in * non secret channels. */ do_names(sptr, chptr, showingdelayed|NAMES_VIS|NAMES_EON); } } else send_reply(sptr, RPL_ENDOFNAMES, para); } while ((para = s) != NULL); return 1; }
void do_names(struct Client* sptr, struct Channel* chptr, int filter) { int mlen; int idx; int flag; int needs_space; int len; char buf[BUFSIZE]; struct Client *c2ptr; struct Membership* member; assert(chptr); assert(sptr); assert((filter&NAMES_ALL) != (filter&NAMES_VIS)); /* Tag Pub/Secret channels accordingly. */ strcpy(buf, "* "); if (PubChannel(chptr)) *buf = '='; else if (SecretChannel(chptr)) *buf = '@'; len = strlen(chptr->chname); strcpy(buf + 2, chptr->chname); strcpy(buf + 2 + len, " :"); idx = len + 4; flag = 1; needs_space = 0; if (!ShowChannel(sptr, chptr)) /* Don't list private channels unless we are on them. */ return; /* Iterate over all channel members, and build up the list. */ mlen = strlen(cli_name(&me)) + 10 + strlen(cli_name(sptr)); for (member = chptr->members; member; member = member->next_member) { c2ptr = member->user; if (((filter&NAMES_VIS)!=0) && IsInvisible(c2ptr)) continue; if (IsZombie(member) && member->user != sptr) continue; if (IsDelayedJoin(member) && (member->user != sptr) && !(filter & NAMES_DEL)) continue; if ((!IsDelayedJoin(member) || (member->user == sptr)) && (filter & NAMES_DEL)) continue; if (needs_space) buf[idx++] = ' '; needs_space=1; if (IsZombie(member)) buf[idx++] = '!'; else if (IsChanOp(member)) buf[idx++] = '@'; else if (HasVoice(member)) buf[idx++] = '+'; strcpy(buf + idx, cli_name(c2ptr)); idx += strlen(cli_name(c2ptr)); flag = 1; if (mlen + idx + NICKLEN + 5 > BUFSIZE) /* space, modifier, nick, \r \n \0 */ { send_reply(sptr, (filter & NAMES_DEL) ? RPL_DELNAMREPLY : RPL_NAMREPLY, buf); idx = len + 4; flag = 0; needs_space=0; } } if (flag) send_reply(sptr, (filter & NAMES_DEL) ? RPL_DELNAMREPLY : RPL_NAMREPLY, buf); if (filter&NAMES_EON) send_reply(sptr, RPL_ENDOFNAMES, chptr->chname); }
DLLFUNC CMD_FUNC(m_names) { int uhnames = (MyConnect(sptr) && SupportUHNAMES(sptr)); // cache UHNAMES support int bufLen = NICKLEN + (!uhnames ? 0 : (1 + USERLEN + 1 + HOSTLEN)); int mlen = strlen(me.name) + bufLen + 7; aChannel *chptr; aClient *acptr; int member; Member *cm; int idx, flag = 1, spos; char *s, *para = parv[1]; char nuhBuffer[NICKLEN+USERLEN+HOSTLEN+3]; if (parc < 2 || !MyConnect(sptr)) { sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], "*"); return 0; } for (s = para; *s; s++) { if (*s == ',') { if (strlen(para) > TRUNCATED_NAMES) para[TRUNCATED_NAMES] = '\0'; sendto_realops("names abuser %s %s", get_client_name(sptr, FALSE), para); sendto_one(sptr, err_str(ERR_TOOMANYTARGETS), me.name, sptr->name, "NAMES"); return 0; } } chptr = find_channel(para, (aChannel *)NULL); if (!chptr || (!ShowChannel(sptr, chptr) && !OPCanSeeSecret(sptr))) { sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], para); return 0; } /* cache whether this user is a member of this channel or not */ member = IsMember(sptr, chptr); if (PubChannel(chptr)) buf[0] = '='; else if (SecretChannel(chptr)) buf[0] = '@'; else buf[0] = '*'; idx = 1; buf[idx++] = ' '; for (s = chptr->chname; *s; s++) buf[idx++] = *s; buf[idx++] = ' '; buf[idx++] = ':'; /* If we go through the following loop and never add anything, we need this to be empty, otherwise spurious things from the LAST /names call get stuck in there.. - lucas */ buf[idx] = '\0'; spos = idx; /* starting point in buffer for names! */ for (cm = chptr->members; cm; cm = cm->next) { acptr = cm->cptr; if (IsInvisible(acptr) && !member && !IsNetAdmin(sptr)) continue; if (chptr->mode.mode & MODE_AUDITORIUM) if (!is_chan_op(sptr, chptr) && !is_chanprot(sptr, chptr) && !is_chanowner(sptr, chptr)) if (!(cm-> flags & (CHFL_CHANOP | CHFL_CHANPROT | CHFL_CHANOWNER)) && acptr != sptr) continue; if (!SupportNAMESX(sptr)) { /* Standard NAMES reply */ #ifdef PREFIX_AQ if (cm->flags & CHFL_CHANOWNER) buf[idx++] = '~'; else if (cm->flags & CHFL_CHANPROT) buf[idx++] = '&'; else #endif if (cm->flags & CHFL_CHANOP) buf[idx++] = '@'; else if (cm->flags & CHFL_HALFOP) buf[idx++] = '%'; else if (cm->flags & CHFL_VOICE) buf[idx++] = '+'; } else { /* NAMES reply with all rights included (NAMESX) */ #ifdef PREFIX_AQ if (cm->flags & CHFL_CHANOWNER) buf[idx++] = '~'; if (cm->flags & CHFL_CHANPROT) buf[idx++] = '&'; #endif if (cm->flags & CHFL_CHANOP) buf[idx++] = '@'; if (cm->flags & CHFL_HALFOP) buf[idx++] = '%'; if (cm->flags & CHFL_VOICE) buf[idx++] = '+'; } if (!uhnames) { s = acptr->name; } else { strlcpy(nuhBuffer, make_nick_user_host(acptr->name, acptr->user->username, GetHost(acptr)), bufLen + 1); s = nuhBuffer; } /* 's' is intialized above to point to either acptr->name (normal), * or to nuhBuffer (for UHNAMES). */ for (; *s; s++) buf[idx++] = *s; buf[idx++] = ' '; buf[idx] = '\0'; flag = 1; if (mlen + idx + bufLen > BUFSIZE - 7) { sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf); idx = spos; flag = 0; } } if (flag) sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf); sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], para); return 0; }
/* * 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); }
/* * Search and return as many people as matched by the wild 'nick'. * returns the number of people found (or, obviously, 0, if none where * found). */ static int do_wilds(struct Client* sptr, char *nick, int count, int parc) { struct Client *acptr; /* Current client we're considering */ struct User *user; /* the user portion of the client */ const char *name; /* the name of this client */ struct Membership* chan; int invis; /* does +i apply? */ int member; /* Is this user on any channels? */ int showperson; /* Should we show this person? */ int found = 0 ; /* How many were found? */ /* Ech! This is hideous! */ for (acptr = GlobalClientList; (acptr = next_client(acptr, nick)); acptr = cli_next(acptr)) { if (!IsRegistered(acptr)) continue; if (IsServer(acptr)) continue; /* * I'm always last :-) and acptr->next == 0!! * * Isomer: Does this strike anyone else as being a horrible hideous * hack? */ if (IsMe(acptr)) { assert(!cli_next(acptr)); break; } /* * 'Rules' established for sending a WHOIS reply: * * - if wildcards are being used don't send a reply if * the querier isn't any common channels and the * client in question is invisible. * * - only send replies about common or public channels * the target user(s) are on; */ user = cli_user(acptr); name = (!*(cli_name(acptr))) ? "?" : cli_name(acptr); assert(user); invis = (acptr != sptr) && IsInvisible(acptr); member = (user && user->channel) ? 1 : 0; showperson = !invis && !member; /* Should we show this person now? */ if (showperson) { found++; do_whois(sptr, acptr, parc); if (count+found>MAX_WHOIS_LINES) return found; continue; } /* Step through the channels this user is on */ for (chan = user->channel; chan; chan = chan->next_channel) { struct Channel *chptr = chan->channel; /* If this is a public channel, show the person */ if (!invis && PubChannel(chptr)) { showperson = 1; break; } /* if this channel is +p and not +s, show them */ if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr)) { showperson = 1; break; } member = find_channel_member(sptr, chptr) ? 1 : 0; if (invis && !member) continue; /* If sptr isn't really on this channel, skip it */ if (IsZombie(chan)) continue; /* Is this a common channel? */ if (member) { showperson = 1; break; } } /* of for (chan in channels) */ /* Don't show this person */ if (!showperson) continue; do_whois(sptr, acptr, parc); found++; if (count+found>MAX_WHOIS_LINES) return found; } /* of global client list */ return found; }