X-Git-Url: http://git.pk910.de/?p=ircu2.10.12-pk.git;a=blobdiff_plain;f=ircd%2Fwhocmds.c;fp=ircd%2Fwhocmds.c;h=0b166ba0bb0ebd7e8a0dbc94d4382a77efc952fc;hp=0000000000000000000000000000000000000000;hb=0400a5a6479398d82526785c18c0df8bc8b92dce;hpb=d17e10da972ce5776c60b4c317267c6abe0e1ead diff --git a/ircd/whocmds.c b/ircd/whocmds.c new file mode 100644 index 0000000..0b166ba --- /dev/null +++ b/ircd/whocmds.c @@ -0,0 +1,278 @@ +/* + * IRC - Internet Relay Chat, ircd/s_user.c (formerly ircd/s_msg.c) + * Copyright (C) 1990 Jarkko Oikarinen and + * University of Oulu, Computing Center + * + * See file AUTHORS in IRC package for additional names of + * the programmers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/** @file + * @brief Support functions for /WHO-like commands. + * @version $Id$ + */ +#include "config.h" + +#include "whocmds.h" +#include "channel.h" +#include "client.h" +#include "hash.h" +#include "ircd.h" +#include "ircd_chattr.h" +#include "ircd_features.h" +#include "ircd_reply.h" +#include "ircd_snprintf.h" +#include "ircd_string.h" +#include "list.h" +#include "match.h" +#include "numeric.h" +#include "numnicks.h" +#include "querycmds.h" +#include "random.h" +#include "s_bsd.h" +#include "s_conf.h" +#include "s_misc.h" +#include "s_user.h" +#include "send.h" +#include "struct.h" +#include "sys.h" +#include "userload.h" +#include "version.h" +#include "whowas.h" +#include "msg.h" + +#include +#include +#include +#include +#include +#include + +/** Send a WHO reply to a client who asked. + * @param[in] sptr Client who is searching for other users. + * @param[in] acptr Client who may be shown to \a sptr. + * @param[in] repchan Shared channel that provides visibility. + * @param[in] fields Bitmask of WHO_FIELD_* values, indicating what to show. + * @param[in] qrt Query type string (ignored unless \a fields & WHO_FIELD_QTY). + */ +void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan, + int fields, char* qrt) +{ + char *p1; + struct Membership *chan = 0; + + 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 (repchan) + { + chan = find_channel_member(acptr, repchan); + } + else if ((!fields || (fields & (WHO_FIELD_CHA | WHO_FIELD_FLA))) + && !IsChannelService(acptr)) + { + for (chan = cli_user(acptr)->channel; chan; chan = chan->next_channel) + if (PubChannel(chan->channel) && + (acptr == sptr || !IsZombie(chan))) + break; + } + + /* 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 = (chan ? chan->channel->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 = HasHiddenHost(acptr) && !IsAnOper(sptr) ? + feature_str(FEAT_HIDDEN_IP) : + ircd_ntoa(&cli_ip(acptr)); + *(p1++) = ' '; + while ((*p2) && (*(p1++) = *(p2++))); + } + + if (!fields || (fields & WHO_FIELD_HOS)) + { + char *p2 = cli_user(acptr)->host; + *(p1++) = ' '; + while ((*p2) && (*(p1++) = *(p2++))); + } + + if (!fields || (fields & WHO_FIELD_SER)) + { + const char *p2 = (feature_bool(FEAT_HIS_WHO_SERVERNAME) && !IsAnOper(sptr)) ? + feature_str(FEAT_HIS_SERVERNAME) : + 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 SeeOper(sptr,acptr) + *(p1++) = '*'; + if (!chan) { + /* No flags possible for the channel, so skip them all. */ + } + else 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 (IsChanOp(chan)) + *(p1++) = '@'; + if (HasVoice(chan)) + *(p1++) = '+'; + if (IsZombie(chan)) + *(p1++) = '!'; + if (IsDelayedJoin(chan)) + *(p1++) = '<'; + } + else { + if (IsChanOp(chan)) + *(p1++) = '@'; + else if (HasVoice(chan)) + *(p1++) = '+'; + else if (IsZombie(chan)) + *(p1++) = '!'; + else if (IsDelayedJoin(chan)) + *(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 (!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) && + (IsAnOper(sptr) || !feature_bool(FEAT_HIS_WHO_SERVERNAME) || + acptr == sptr)) + p1 += ircd_snprintf(0, p1, 11, "%d", + CurrentTime - cli_user(acptr)->last); + else + *p1++ = '0'; + } + + if (fields & WHO_FIELD_ACC) + { + char *p2 = cli_user(acptr)->account; + *(p1++) = ' '; + if (*p2) + while ((*p2) && (*(p1++) = *(p2++))); + else + *(p1++) = '0'; + } + + if (fields & WHO_FIELD_OPL) + { + if (!chan || !IsChanOp(chan)) + { + strcpy(p1, " n/a"); + p1 += 4; + } + else + { + int vis_level = MAXOPLEVEL; + if ((IsGlobalChannel(chan->channel->chname) ? IsOper(sptr) : IsAnOper(sptr)) + || is_chan_op(sptr, chan->channel)) + vis_level = OpLevel(chan); + p1 += ircd_snprintf(0, p1, 5, " %d", vis_level); + } + } + + 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++))); + } + + /* 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); +}