/************************************************************************
 *   IRC - Internet Relay Chat, modules/m_whois.c
 *
 *   Copyright (C) 2000-2003 TR-IRCD Development
 *
 *   Copyright (C) 1990 Jarkko Oikarinen and
 *                      University of Oulu, Co Center
 *
 *   See file AUTHORS in IRC package for additional names of
 *   the programmers.
 *
 *   This program is free softwmare; 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 2, 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.
 */

#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include "h.h"
#include "s_conf.h"
#include "chanmode.h"

static char buf[BUFSIZE];

static char *token = TOK1_WHOIS;

static struct Message _msgtab[] = {
    {MSG_WHOIS, 0, MAXPARA, M_SLOW, 0L,
     m_unregistered, m_whois, m_whois, m_whois, m_whois}
};

#ifndef STATIC_MODULES

char *_version = "$Revision: 1.4 $";

void _modinit(void)
{
    mod_add_cmd(_msgtab);
    tok1_msgtab[(u_char) *token].msg = _msgtab;
}

void _moddeinit(void)
{
    mod_del_cmd(_msgtab);
    tok1_msgtab[(u_char) *token].msg = NULL;
}
#else
void m_whois_init(void)
{
    mod_add_cmd(_msgtab);
    tok1_msgtab[(u_char) *token].msg = _msgtab;
}
#endif

/*
 * * m_whois *        parv[0] = sender prefix *       parv[1] = nickname
 * masklist
 */
int m_whois(aClient *cptr, aClient *sptr, int parc, char *parv[])
{

    dlink_node *lp;
    anUser *user;
    aClient *acptr, *acptr2;
    aChannel *chptr;
    char *nick, *tmp, *name;
    char *p = NULL;
    int len, mlen;
    char out[HOSTLEN];		/* TimeMr14C */

    static anUser UnknownUser;

    strlcpy_irc(UnknownUser.username, "unknown", 7);
    strlcpy_irc(UnknownUser.fakehost, "unknown", 7);
    strlcpy_irc(UnknownUser.host, "unknown", 7);

    if (parc < 2) {
	send_me_numeric(sptr, ERR_NONICKNAMEGIVEN);
	return 0;
    }

    if (parc > 2) {
	if (hunt_server(cptr, sptr, ":%s %s %s :%s", TOK1_WHOIS, 1, parc, parv)
	    != HUNTED_ISME)
	    return 0;
	parv[1] = parv[2];
    }

    for (tmp = parv[1]; (nick = strtoken(&p, tmp, ",")); tmp = NULL) {
    int invis, member, showchan;

	acptr = find_client(nick);
	if (!acptr || !IsPerson(acptr)) {
	    send_me_numeric(sptr, ERR_NOSUCHNICK, nick);
	    continue;
	}

	user = acptr->user ? acptr->user : &UnknownUser;
	name = (!*acptr->name) ? "?" : acptr->name;
	invis = IsInvisible(acptr);
	member = (user->channel.head) ? 1 : 0;

	acptr2 = find_server(user->server);

	if (IsAnOper(acptr) || IsHelpop(acptr))
	    send_me_notice(acptr, ":%C did a /whois on you ", sptr);

	send_me_numeric(sptr, RPL_WHOISUSER, name, user->username,
			IsFake(acptr) ? acptr->user->fakehost : acptr->user->host,
			acptr->info);

	if ((IsSeeHidden(sptr) || (sptr == acptr)) && IsFake(acptr))
	    send_me_numeric(sptr, RPL_REALHOST, name, user->host);

	if (IsOperFakehost(acptr) && IsSeeHidden(sptr)) {
	    send_me_numeric(sptr, RPL_WHOISACTUALLY, name,
			    user->username, user->real_oper_host, user->real_oper_ip);
	} else if (IN_ADDR(acptr->ip) && IsSeeHidden(sptr)) {
            send_me_numeric(sptr, RPL_WHOISACTUALLY, name, acptr->username,
                            user->host, 
			    (IsClientIpv6(acptr) ? acptr->hostip : inetntoa((char *) &IN_ADDR(acptr->ip))));
        }

	mlen = strlen(me.name) + strlen(parv[0]) + 6 + strlen(name);
	for (len = 0, *buf = '\0', lp = user->channel.head; lp; lp = lp->next) {
	    chptr = lp->data;
	    if (IsChanAnon(chptr))
		continue;
	    showchan = ShowChannel(sptr, chptr);
	    if ((showchan && !IsWhoisHideChan(acptr)) || IsSeeHidden(sptr) || (acptr == sptr)) {
		if (len + strlen(chptr->chname)
		    > (size_t) BUFSIZE - 4 - mlen) {
		    send_me_numeric(sptr, RPL_WHOISCHANNELS, name, buf);
		    *buf = '\0';
		    len = 0;
		}
		if (!showchan)
		    *(buf + len++) = '%';
		if (!IsChanHideOps(chptr) || IsSeeHidden(sptr)) {
		    int f = get_flags(acptr, chptr);
		    if (f & CHFL_OWNER)
			*(buf + len++) = '.';
		    else if (f & CHFL_CHANOP)
			*(buf + len++) = '@';
		    else if (f & CHFL_HALFOP)
			*(buf + len++) = '%';
		    else if (f & CHFL_VOICE)
			*(buf + len++) = '+';
		}
		/* no protect case, because it is not a user-seen prefix */
		/* -TimeMr14C */
		if (len)
		    *(buf + len) = '\0';
		strcpy(buf + len, chptr->chname);
		len += strlen(chptr->chname);
		strcat(buf + len, " ");
		len++;
	    }
	}
	if (buf[0] != '\0')
	    send_me_numeric(sptr, RPL_WHOISCHANNELS, name, buf);

	if (MyClient(acptr) && MyClient(sptr))
	    send_me_numeric(sptr, RPL_WHOISSERVER, name, me.name, me.info);
	else if (MyClient(acptr) && ServerHide.enable)
	    send_me_numeric(sptr, RPL_WHOISSERVER, name, stealth_server(user->server, out),
			    ServerInfo.networkdesc);
	else if (acptr2 && WillHideName(acptr2))
	    send_me_numeric(sptr, RPL_WHOISSERVER, name, stealth_server(user->server, out),
			    ServerInfo.networkdesc);
	else if (acptr2)
	    send_me_numeric(sptr, RPL_WHOISSERVER, name, user->server, acptr2->info);
	else
	    send_me_numeric(sptr, RPL_WHOISSERVER, name, user->server, "*Not On This Net*");

	if (IsRegNick(acptr))
	    send_me_numeric(sptr, RPL_WHOISREGNICK, name);
	if (IsZombie(acptr))
	    send_me_numeric(sptr, RPL_WHOISZOMBIE, name);
	if (user->away)
	    send_me_numeric(sptr, RPL_AWAY, name, user->away);
#ifdef HAVE_ENCRYPTION_ON
	if (IsSSL(acptr))
	    send_me_numeric(sptr, RPL_USINGSSL, name);
#endif
	buf[0] = '\0';
	if (IsAnOper(acptr))
	    strcat(buf, "an IRC Operator");
	if (IsAdmin(acptr))
	    strcat(buf, " - Server Administrator");
	else if (IsSAdmin(acptr))
	    strcat(buf, " - Services Administrator");
	if (buf[0])
	    send_me_numeric(sptr, RPL_WHOISOPERATOR, name, buf);
        if (IsHelpop(acptr))
            send_me_numeric(sptr, RPL_WHOISHELPFUL, name, ServerInfo.networkname);
    	if (IsDenyPrivmsg(acptr))
	    send_me_numeric(sptr, RPL_WHOISNOPRIVMSGS, name);
	if (acptr->user && MyConnect(acptr) && (!IsPrivate(acptr) || IsSeeHidden(sptr) || (sptr == acptr)))
	    send_me_numeric(sptr, RPL_WHOISIDLE, name, timeofday - user->last, acptr->firsttime);
    }
    send_me_numeric(sptr, RPL_ENDOFWHOIS, parv[1]);
    return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1