]> jfr.im git - solanum.git/commitdiff
ircd: import modified version of ratbox 3.1 whowas code
authorWilliam Pitcock <redacted>
Sat, 23 Jan 2016 16:16:34 +0000 (11:16 -0500)
committerWilliam Pitcock <redacted>
Sat, 23 Jan 2016 16:16:34 +0000 (11:16 -0500)
12 files changed:
include/client.h
include/messages.h
include/whowas.h
ircd/client.c
ircd/ircd.c
ircd/s_user.c
ircd/whowas.c
modules/core/m_kill.c
modules/core/m_nick.c
modules/m_services.c
modules/m_stats.c
modules/m_whowas.c

index 4300500e3e1c9ae4ec1f0f200d214390c60f8470..0261c7753af859d6f82b534998a1c121fca1c552 100644 (file)
@@ -117,7 +117,8 @@ struct Client
        struct Client *servptr; /* Points to server this Client is on */
        struct Client *from;    /* == self, if Local Client, *NEVER* NULL! */
 
-       struct Whowas *whowas;  /* Pointers to whowas structs */
+       rb_dlink_list whowas_clist;
+
        time_t tsinfo;          /* TS on the nick, SVINFO on server */
        unsigned int umodes;    /* opers, normal users subset */
        unsigned int flags;     /* client flags */
index 8ae8ee87b0c3ea872419d9e38aefd7d3ab011b72..d54c81be40095e9b7024b25535678bf7c2855ba4 100644 (file)
 #define NUMERIC_STR_366      ":%s 366 %s %s :End of /NAMES list."
 #define NUMERIC_STR_367      ":%s 367 %s %s %s %s %lu"
 #define NUMERIC_STR_368      ":%s 368 %s %s :End of Channel Ban List"
-#define NUMERIC_STR_369      ":%s 369 %s %s :End of WHOWAS"
+#define NUMERIC_STR_369      "%s :End of WHOWAS"
 #define NUMERIC_STR_371      ":%s"
 #define NUMERIC_STR_372      ":%s 372 %s :- %s"
 #define NUMERIC_STR_374      ":End of /INFO list."
 #define NUMERIC_STR_403      "%s :No such channel"
 #define NUMERIC_STR_404      "%s :Cannot send to channel"
 #define NUMERIC_STR_405      ":%s 405 %s %s :You have joined too many channels"
-#define NUMERIC_STR_406      ":%s 406 %s %s :There was no such nickname"
+#define NUMERIC_STR_406      ":%s :There was no such nickname"
 #define NUMERIC_STR_407      ":%s 407 %s %s :Too many recipients."
 #define NUMERIC_STR_409      ":%s 409 %s :No origin specified"
 #define NUMERIC_STR_410      ":%s 410 %s %s :Invalid CAP subcommand"
index ca3dde9f715b829d43c63da63f0709b6744e046a..9d75d1cd98a44762fd7e7c1218e623f90ab75574 100644 (file)
 
 #include "setup.h"
 
-/*
- * Whowas hash table size
- *
- */
-#define WW_MAX_BITS 16
-#define WW_MAX 65536
-
 struct User;
 struct Client;
 
@@ -48,7 +41,10 @@ struct Client;
  */
 struct Whowas
 {
-       int hashv;
+       struct whowas_top *wtop;
+       rb_dlink_node wnode;            /* for the wtop linked list */
+       rb_dlink_node cnode;            /* node for online clients */
+       rb_dlink_node whowas_node;      /* node for the whowas linked list */
        char name[NICKLEN + 1];
        char username[USERLEN + 1];
        char hostname[HOSTLEN + 1];
@@ -59,10 +55,6 @@ struct Whowas
        const char *servername;
        time_t logoff;
        struct Client *online;  /* Pointer to new nickname for chasing or NULL */
-       struct Whowas *next;    /* for hash table... */
-       struct Whowas *prev;    /* for hash table... */
-       struct Whowas *cnext;   /* for client struct linked list */
-       struct Whowas *cprev;   /* for client struct linked list */
 };
 
 /* Flags */
@@ -72,7 +64,7 @@ struct Whowas
 /*
 ** initwhowas
 */
-extern void initwhowas(void);
+extern void whowas_init(void);
 
 /*
 ** add_history
@@ -81,7 +73,7 @@ extern void initwhowas(void);
 **      Client must be a fully registered user (specifically,
 **      the user structure must have been allocated).
 */
-void add_history(struct Client *, int);
+void whowas_add_history(struct Client *, int);
 
 /*
 ** off_history
@@ -90,7 +82,7 @@ void add_history(struct Client *, int);
 **      structures and it must know when they cease to exist. This
 **      also implicitly calls AddHistory.
 */
-void off_history(struct Client *);
+void whowas_off_history(struct Client *);
 
 /*
 ** get_history
@@ -98,18 +90,12 @@ void off_history(struct Client *);
 **      nickname within the timelimit. Returns NULL, if no
 **      one found...
 */
-struct Client *get_history(const char *, time_t);
+struct Client *whowas_get_history(const char *, time_t);
                                        /* Nick name */
                                        /* Time limit in seconds */
 
-/*
-** for debugging...counts related structures stored in whowas array.
-*/
-void count_whowas_memory(size_t *, size_t *);
-
-/* XXX m_whowas.c in modules needs these */
-extern struct Whowas WHOWAS[];
-extern struct Whowas *WHOWASHASH[];
-extern unsigned int hash_whowas_name(const char *name);
+rb_dlink_list *whowas_get_list(const char *name);
+void whowas_set_size(int whowas_length);
+void whowas_memory_usage(size_t *count, size_t *memused);
 
 #endif /* INCLUDED_whowas_h */
index 2fc1f22604fc210d6dff100cf342306c15669a6c..1948e995e60931d03cdd3ff273b2757c35f9f7df 100644 (file)
@@ -672,7 +672,7 @@ resv_nick_fnc(const char *mask, const char *reason, int temp_time)
 
                        /* Do all of the nick-changing gymnastics. */
                        client_p->tsinfo = rb_current_time();
-                       add_history(client_p, 1);
+                       whowas_add_history(client_p, 1);
 
                        monitor_signoff(client_p);
 
@@ -872,7 +872,7 @@ find_chasing(struct Client *source_p, const char *user, int *chasing)
        if(who || IsDigit(*user))
                return who;
 
-       if(!(who = get_history(user, (long) KILLCHASETIMELIMIT)))
+       if(!(who = whowas_get_history(user, (long) KILLCHASETIMELIMIT)))
        {
                sendto_one_numeric(source_p, ERR_NOSUCHNICK,
                                   form_str(ERR_NOSUCHNICK), user);
@@ -1247,8 +1247,8 @@ exit_generic_client(struct Client *client_p, struct Client *source_p, struct Cli
        /* Clean up allow lists */
        del_all_accepts(source_p);
 
-       add_history(source_p, 0);
-       off_history(source_p);
+       whowas_add_history(source_p, 0);
+       whowas_off_history(source_p);
 
        monitor_signoff(source_p);
 
index 9fb9958e833513dd124764b83603a26f0e206c2c..b55ce238e827a9f1c6ed0a5960bb36d3ac71d969 100644 (file)
@@ -653,7 +653,7 @@ charybdis_main(int argc, char *argv[])
        init_hook();
        init_channels();
        initclass();
-       initwhowas();
+       whowas_init();
        init_reject();
        init_cache();
        init_monitor();
index 55a0bb557771e4250e7d6d9ff78c12e724c5a856..b2e3829c19bd693ffe68a4fcbec3b9ab2911b21d 100644 (file)
@@ -1513,7 +1513,7 @@ change_nick_user_host(struct Client *target_p,    const char *nick, const char *use
        rb_strlcpy(target_p->host, host, sizeof target_p->host);
 
        if (changed)
-               add_history(target_p, 1);
+               whowas_add_history(target_p, 1);
 
        del_from_client_hash(target_p->name, target_p);
        rb_strlcpy(target_p->name, nick, NICKLEN);
index 716bdccd48a4cd94f57c9a51244fe0468afa4ca5..0bcd88fc2496cd1376be6fb7e39220f8edb3c30f 100644 (file)
@@ -4,7 +4,8 @@
  *
  *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
  *  Copyright (C) 1996-2002 Hybrid Development Team
- *  Copyright (C) 2002-2005 ircd-ratbox development team
+ *  Copyright (C) 2002-2012 ircd-ratbox development team
+ *  Copyright (C) 2016 William Pitcock <nenolod@dereferenced.org>
  *
  *  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
  *
  *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
  *  USA
- *
- *  $Id: whowas.c 1717 2006-07-04 14:41:11Z jilles $
  */
 
 #include "stdinc.h"
-
-#include "whowas.h"
-#include "client.h"
-#include "common.h"
 #include "hash.h"
+#include "whowas.h"
 #include "match.h"
 #include "ircd.h"
-#include "ircd_defs.h"
 #include "numeric.h"
+#include "s_assert.h"
 #include "s_serv.h"
 #include "s_user.h"
 #include "send.h"
 #include "s_conf.h"
+#include "client.h"
+#include "send.h"
+#include "logger.h"
 #include "scache.h"
-#include "s_assert.h"
+#include "irc_radixtree.h"
 
-/* internally defined function */
-static void add_whowas_to_clist(struct Whowas **, struct Whowas *);
-static void del_whowas_from_clist(struct Whowas **, struct Whowas *);
-static void add_whowas_to_list(struct Whowas **, struct Whowas *);
-static void del_whowas_from_list(struct Whowas **, struct Whowas *);
+struct whowas_top
+{
+       char *name;
+       rb_dlink_list wwlist;
+};
 
-struct Whowas WHOWAS[NICKNAMEHISTORYLENGTH];
-struct Whowas *WHOWASHASH[WW_MAX];
+static struct irc_radixtree *whowas_tree = NULL;
+static rb_dlink_list whowas_list = {NULL, NULL, 0};
+static unsigned int whowas_list_length = NICKNAMEHISTORYLENGTH;
+static void whowas_trim(void *unused);
 
-static int whowas_next = 0;
+static void
+whowas_free_wtop(struct whowas_top *wtop)
+{
+       if(rb_dlink_list_length(&wtop->wwlist) == 0)
+       {
+               irc_radixtree_delete(whowas_tree, wtop->name);
+               rb_free(wtop->name);
+               rb_free(wtop);
+       }
+}
 
-unsigned int hash_whowas_name(const char *name)
+static struct whowas_top *
+whowas_get_top(const char *name)
 {
-       return fnv_hash_upper((const unsigned char *) name, WW_MAX_BITS);
+       struct whowas_top *wtop;
+
+       wtop = irc_radixtree_retrieve(whowas_tree, name);
+       if (wtop != NULL)
+               return wtop;
+
+       wtop = rb_malloc(sizeof(struct whowas_top));
+       wtop->name = rb_strdup(name);
+       irc_radixtree_add(whowas_tree, wtop->name, wtop);
+
+       return wtop;
 }
 
-void add_history(struct Client *client_p, int online)
+rb_dlink_list *
+whowas_get_list(const char *name)
 {
-       struct Whowas *who = &WHOWAS[whowas_next];
+       struct whowas_top *wtop;
+       wtop = irc_radixtree_retrieve(whowas_tree, name);
+       if(wtop == NULL)
+               return NULL;
+       return &wtop->wwlist;
+}
 
+void
+whowas_add_history(struct Client *client_p, int online)
+{
+       struct whowas_top *wtop;
+       struct Whowas *who;
        s_assert(NULL != client_p);
 
        if(client_p == NULL)
                return;
 
-       if(who->hashv != -1)
-       {
-               if(who->online)
-                       del_whowas_from_clist(&(who->online->whowas), who);
-               del_whowas_from_list(&WHOWASHASH[who->hashv], who);
-       }
-       who->hashv = hash_whowas_name(client_p->name);
+       /* trim some of the entries if we're getting well over our history length */
+       if(rb_dlink_list_length(&whowas_list) > whowas_list_length + 100)
+               whowas_trim(NULL);
+
+       wtop = whowas_get_top(client_p->name);
+       who = rb_malloc(sizeof(struct Whowas));
+       who->wtop = wtop;
        who->logoff = rb_current_time();
-       /*
-        * NOTE: strcpy ok here, the sizes in the client struct MUST
-        * match the sizes in the whowas struct
-        */
+
        rb_strlcpy(who->name, client_p->name, sizeof(who->name));
-       strcpy(who->username, client_p->username);
-       strcpy(who->hostname, client_p->host);
-       strcpy(who->realname, client_p->info);
-       strcpy(who->suser, client_p->user->suser);
-       strcpy(who->sockhost, client_p->sockhost);
+       rb_strlcpy(who->username, client_p->username, sizeof(who->username));
+       rb_strlcpy(who->hostname, client_p->host, sizeof(who->hostname));
+       rb_strlcpy(who->realname, client_p->info, sizeof(who->realname));
+       rb_strlcpy(who->sockhost, client_p->sockhost, sizeof(who->sockhost));
+
        who->flags = (IsIPSpoof(client_p) ? WHOWAS_IP_SPOOFING : 0) |
                (IsDynSpoof(client_p) ? WHOWAS_DYNSPOOF : 0);
 
+       /* this is safe do to with the servername cache */
        who->servername = scache_get_name(client_p->servptr->serv->nameinfo);
 
        if(online)
        {
                who->online = client_p;
-               add_whowas_to_clist(&(client_p->whowas), who);
+               rb_dlinkAdd(who, &who->cnode, &client_p->whowas_clist);
        }
        else
                who->online = NULL;
-       add_whowas_to_list(&WHOWASHASH[who->hashv], who);
-       whowas_next++;
-       if(whowas_next == NICKNAMEHISTORYLENGTH)
-               whowas_next = 0;
+
+       rb_dlinkAdd(who, &who->wnode, &wtop->wwlist);
+       rb_dlinkAdd(who, &who->whowas_node, &whowas_list);
 }
 
-void off_history(struct Client *client_p)
+
+void
+whowas_off_history(struct Client *client_p)
 {
-       struct Whowas *temp, *next;
+       rb_dlink_node *ptr, *next;
 
-       for (temp = client_p->whowas; temp; temp = next)
+       RB_DLINK_FOREACH_SAFE(ptr, next, client_p->whowas_clist.head)
        {
-               next = temp->cnext;
-               temp->online = NULL;
-               del_whowas_from_clist(&(client_p->whowas), temp);
+               struct Whowas *who = ptr->data;
+               who->online = NULL;
+               rb_dlinkDelete(&who->cnode, &client_p->whowas_clist);
        }
 }
 
-struct Client *get_history(const char *nick, time_t timelimit)
+struct Client *
+whowas_get_history(const char *nick, time_t timelimit)
 {
-       struct Whowas *temp;
-       int blah;
+       struct whowas_top *wtop;
+       rb_dlink_node *ptr;
+
+       wtop = irc_radixtree_retrieve(whowas_tree, nick);
+       if(wtop == NULL)
+               return NULL;
 
        timelimit = rb_current_time() - timelimit;
-       blah = hash_whowas_name(nick);
-       temp = WHOWASHASH[blah];
-       for (; temp; temp = temp->next)
+
+       RB_DLINK_FOREACH_PREV(ptr, wtop->wwlist.tail)
        {
-               if(irccmp(nick, temp->name))
-                       continue;
-               if(temp->logoff < timelimit)
-                       continue;
-               return temp->online;
+               struct Whowas *who = ptr->data;
+               if(who->logoff >= timelimit)
+               {
+                       return who->online;
+               }
        }
+
        return NULL;
 }
 
-void count_whowas_memory(size_t * wwu, size_t * wwum)
+static void
+whowas_trim(void *unused)
 {
-       *wwu = NICKNAMEHISTORYLENGTH;
-       *wwum = NICKNAMEHISTORYLENGTH * sizeof(struct Whowas);
-}
+       long over;
 
-void
-initwhowas()
-{
-       int i;
+       if(rb_dlink_list_length(&whowas_list) < whowas_list_length)
+               return;
+       over = rb_dlink_list_length(&whowas_list) - whowas_list_length;
 
-       for (i = 0; i < NICKNAMEHISTORYLENGTH; i++)
+       /* remove whowas entries over the configured length */
+       for(long i = 0; i < over; i++)
        {
-               memset((void *) &WHOWAS[i], 0, sizeof(struct Whowas));
-               WHOWAS[i].hashv = -1;
+               if(whowas_list.tail != NULL && whowas_list.tail->data != NULL)
+               {
+                       struct Whowas *twho = whowas_list.tail->data;
+                       if(twho->online != NULL)
+                               rb_dlinkDelete(&twho->cnode, &twho->online->whowas_clist);
+                       rb_dlinkDelete(&twho->wnode, &twho->wtop->wwlist);
+                       rb_dlinkDelete(&twho->whowas_node, &whowas_list);
+                       whowas_free_wtop(twho->wtop);
+                       rb_free(twho);
+               }
        }
-       for (i = 0; i < WW_MAX; i++)
-               WHOWASHASH[i] = NULL;
-}
-
-
-static void
-add_whowas_to_clist(struct Whowas **bucket, struct Whowas *whowas)
-{
-       whowas->cprev = NULL;
-       if((whowas->cnext = *bucket) != NULL)
-               whowas->cnext->cprev = whowas;
-       *bucket = whowas;
 }
 
-static void
-del_whowas_from_clist(struct Whowas **bucket, struct Whowas *whowas)
+void
+whowas_init(void)
 {
-       if(whowas->cprev)
-               whowas->cprev->cnext = whowas->cnext;
-       else
-               *bucket = whowas->cnext;
-       if(whowas->cnext)
-               whowas->cnext->cprev = whowas->cprev;
+       whowas_tree = irc_radixtree_create("whowas", irc_radixtree_irccasecanon);
+       if(whowas_list_length == 0)
+       {
+               whowas_list_length = NICKNAMEHISTORYLENGTH;
+       }
+       rb_event_add("whowas_trim", whowas_trim, NULL, 10);
 }
 
-static void
-add_whowas_to_list(struct Whowas **bucket, struct Whowas *whowas)
+void
+whowas_set_size(int len)
 {
-       whowas->prev = NULL;
-       if((whowas->next = *bucket) != NULL)
-               whowas->next->prev = whowas;
-       *bucket = whowas;
+       whowas_list_length = len;
+       whowas_trim(NULL);
 }
 
-static void
-del_whowas_from_list(struct Whowas **bucket, struct Whowas *whowas)
+void
+whowas_memory_usage(size_t * count, size_t * memused)
 {
-       if(whowas->prev)
-               whowas->prev->next = whowas->next;
-       else
-               *bucket = whowas->next;
-       if(whowas->next)
-               whowas->next->prev = whowas->prev;
+       *count = rb_dlink_list_length(&whowas_list);
+       *memused += *count * sizeof(struct Whowas);
+       *memused += sizeof(struct whowas_top) * irc_radixtree_size(whowas_tree);
 }
index 7c232d5db427103a09ce3eb3120022567af109d6..c6447445cb7f2c55b3090e12eb4fc31707c5ae53 100644 (file)
@@ -102,7 +102,7 @@ mo_kill(struct Client *client_p, struct Client *source_p, int parc, const char *
                 ** rewrite the KILL for this new nickname--this keeps
                 ** servers in synch when nick change and kill collide
                 */
-               if((target_p = get_history(user, (long) KILLCHASETIMELIMIT)) == NULL)
+               if((target_p = whowas_get_history(user, (long) KILLCHASETIMELIMIT)) == NULL)
                {
                        if (strchr(user, '.'))
                                sendto_one_numeric(source_p, ERR_CANTKILLSERVER, form_str(ERR_CANTKILLSERVER));
@@ -221,7 +221,7 @@ ms_kill(struct Client *client_p, struct Client *source_p, int parc, const char *
                 * not an uid, automatically rewrite the KILL for this new nickname.
                 * --this keeps servers in synch when nick change and kill collide
                 */
-               if(IsDigit(*user) || (!(target_p = get_history(user, (long) KILLCHASETIMELIMIT))))
+               if(IsDigit(*user) || (!(target_p = whowas_get_history(user, (long) KILLCHASETIMELIMIT))))
                {
                        sendto_one_numeric(source_p, ERR_NOSUCHNICK,
                                           form_str(ERR_NOSUCHNICK), IsDigit(*user) ? "*" : user);
index a028a58c9ee3b0ff34786e089853886bd54d2822..ab358a151505a5581ef9e78dba95e6af3028fde7 100644 (file)
@@ -685,7 +685,7 @@ change_local_nick(struct Client *client_p, struct Client *source_p,
        /* send the nick change to servers.. */
        if(source_p->user)
        {
-               add_history(source_p, 1);
+               whowas_add_history(source_p, 1);
 
                if (dosend)
                {
@@ -745,7 +745,7 @@ change_remote_nick(struct Client *client_p, struct Client *source_p,
 
        if(source_p->user)
        {
-               add_history(source_p, 1);
+               whowas_add_history(source_p, 1);
                if (dosend)
                {
                        sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld",
index 9d0c789561cf9e4c81f7a43c8511d6aabc2a93e1..ea619b38cbefb54a061ae6c05f95a7d8f850f9de 100644 (file)
@@ -244,7 +244,7 @@ doit:
                                target_p->name, target_p->username,
                                target_p->host, parv[2]);
 
-       add_history(target_p, 1);
+       whowas_add_history(target_p, 1);
        sendto_server(NULL, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld",
                        use_id(target_p), parv[2], (long) target_p->tsinfo);
 
index b1d559674d600c9949a0fd85fc525945f1a78c44..21631e15d1c2f20576530df23c39468ed1597863 100644 (file)
@@ -1267,7 +1267,7 @@ stats_memory (struct Client *source_p)
 
        size_t total_memory = 0;
 
-       count_whowas_memory(&ww, &wwm);
+       whowas_memory_usage(&ww, &wwm);
 
        RB_DLINK_FOREACH(ptr, global_client_list.head)
        {
index 1e9933c65d857f67ac23ca607c1b66ca62781dfe..15032f6de00964d6cdb527134cea325f44a68799 100644 (file)
@@ -58,9 +58,10 @@ DECLARE_MODULE_AV1(whowas, NULL, NULL, whowas_clist, NULL, NULL, "$Revision: 171
 static int
 m_whowas(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
 {
-       struct Whowas *temp;
+       rb_dlink_list *whowas_list;
+       rb_dlink_node *ptr;
        int cur = 0;
-       int max = -1, found = 0;
+       int max = -1;
        char *p;
        const char *nick;
        char tbuf[26];
@@ -76,8 +77,8 @@ m_whowas(struct Client *client_p, struct Client *source_p, int parc, const char
                {
                        sendto_one(source_p, form_str(RPL_LOAD2HI),
                                   me.name, source_p->name, "WHOWAS");
-                       sendto_one(source_p, form_str(RPL_ENDOFWHOWAS),
-                                  me.name, source_p->name, parv[1]);
+                       sendto_one_numeric(source_p, RPL_ENDOFWHOWAS, form_str(RPL_ENDOFWHOWAS),
+                                  parv[1]);
                        return 0;
                }
                else
@@ -101,54 +102,50 @@ m_whowas(struct Client *client_p, struct Client *source_p, int parc, const char
        nick = parv[1];
 
        sendq_limit = get_sendq(client_p) * 9 / 10;
+       whowas_list = whowas_get_list(nick);
 
-       temp = WHOWASHASH[hash_whowas_name(nick)];
-       found = 0;
-       for (; temp; temp = temp->next)
+       if(whowas_list == NULL)
        {
-               if(!irccmp(nick, temp->name))
+               sendto_one_numeric(source_p, ERR_WASNOSUCHNICK, form_str(ERR_WASNOSUCHNICK), nick);
+               sendto_one_numeric(source_p, RPL_ENDOFWHOWAS, form_str(RPL_ENDOFWHOWAS), parv[1]);
+               return 0;
+       }
+
+       RB_DLINK_FOREACH(ptr, whowas_list->head)
+       {
+               struct Whowas *temp = ptr->data;
+               if(cur > 0 && rb_linebuf_len(&client_p->localClient->buf_sendq) > sendq_limit)
                {
-                       if(cur > 0 && rb_linebuf_len(&client_p->localClient->buf_sendq) > sendq_limit)
-                       {
-                               sendto_one(source_p, form_str(ERR_TOOMANYMATCHES),
-                                          me.name, source_p->name, "WHOWAS");
-                               break;
-                       }
-                       sendto_one(source_p, form_str(RPL_WHOWASUSER),
-                                  me.name, source_p->name, temp->name,
-                                  temp->username, temp->hostname, temp->realname);
-                       if (!EmptyString(temp->sockhost) &&
-                                       strcmp(temp->sockhost, "0") &&
-                                       show_ip_whowas(temp, source_p))
-#if 0
-                               sendto_one(source_p, form_str(RPL_WHOWASREAL),
-                                          me.name, source_p->name, temp->name,
-                                          "<untracked>", temp->sockhost);
-#else
-                               sendto_one_numeric(source_p, RPL_WHOISACTUALLY,
-                                                  form_str(RPL_WHOISACTUALLY),
-                                                  temp->name, temp->sockhost);
-#endif
-                       if (!EmptyString(temp->suser))
-                               sendto_one_numeric(source_p, RPL_WHOISLOGGEDIN,
-                                                  "%s %s :was logged in as",
-                                                  temp->name, temp->suser);
-                       sendto_one_numeric(source_p, RPL_WHOISSERVER,
-                                          form_str(RPL_WHOISSERVER),
-                                          temp->name, temp->servername,
-                                          rb_ctime(temp->logoff, tbuf, sizeof(tbuf)));
-                       cur++;
-                       found++;
+                       sendto_one(source_p, form_str(ERR_TOOMANYMATCHES),
+                                  me.name, source_p->name, "WHOWAS");
+                       break;
                }
+
+               sendto_one(source_p, form_str(RPL_WHOWASUSER),
+                          me.name, source_p->name, temp->name,
+                          temp->username, temp->hostname, temp->realname);
+               if (!EmptyString(temp->sockhost) &&
+                               strcmp(temp->sockhost, "0") &&
+                               show_ip_whowas(temp, source_p))
+                       sendto_one_numeric(source_p, RPL_WHOISACTUALLY,
+                                          form_str(RPL_WHOISACTUALLY),
+                                          temp->name, temp->sockhost);
+
+               if (!EmptyString(temp->suser))
+                       sendto_one_numeric(source_p, RPL_WHOISLOGGEDIN,
+                                          "%s %s :was logged in as",
+                                          temp->name, temp->suser);
+
+               sendto_one_numeric(source_p, RPL_WHOISSERVER,
+                                  form_str(RPL_WHOISSERVER),
+                                  temp->name, temp->servername,
+                                  rb_ctime(temp->logoff, tbuf, sizeof(tbuf)));
+
+               cur++;
                if(max > 0 && cur >= max)
                        break;
        }
 
-       if(!found)
-               sendto_one(source_p, form_str(ERR_WASNOSUCHNICK),
-                          me.name, source_p->name, nick);
-
-       sendto_one(source_p, form_str(RPL_ENDOFWHOWAS),
-                  me.name, source_p->name, parv[1]);
+       sendto_one_numeric(source_p, RPL_ENDOFWHOWAS, form_str(RPL_ENDOFWHOWAS), parv[1]);
        return 0;
 }