Logo Search packages:      
Sourcecode: rageircd version File versions  Download package

hash.c

/*
 * RageIRCd: an advanced Internet Relay Chat daemon (ircd).
 * (C) 2000-2005 the RageIRCd Development Team, all rights reserved.
 *
 * This software is free, licensed under the General Public License.
 * Please refer to doc/LICENSE and doc/README for further details.
 *
 * $Id: hash.c,v 1.18.2.1 2004/12/07 03:05:11 pneumatus Exp $
 */

#include "struct.h"
#include "common.h"
#include "sys.h"
#include "hash.h"
#include "h.h"
#include "memory.h"
#include "xmode.h"

static aHashEntry clientTable[U_MAX];
static aHashEntry channelTable[CH_MAX];
static aWatch *watchTable[WATCHHASHSIZE];

static unsigned hash_nick_name(char *name)
{
      unsigned hash = 0;
      int hash2 = 0;
      char lower;

      while (*name++) {
            lower = ToLower(*name);
            hash = (hash << 1) + lower;
            hash2 = (hash2 >> 1) + lower;
      }
      return ((hash & U_MAX_INITIAL_MASK) << BITS_PER_COL) + (hash2 & BITS_PER_COL_MASK);
}

static int hash_channel_name(char *name)
{
      unsigned char *hname = (unsigned char *)name;
      unsigned int hash = 0;
      int hash2 = 0;
      char lower;
      int i = 30;

      while (*hname++ && --i) {
            lower = ToLower(*hname);
            hash = (hash << 1) + lower;
            hash2 = (hash2 >> 1) + lower;
      }
      return ((hash & CH_MAX_INITIAL_MASK) << BITS_PER_COL) + (hash2 & BITS_PER_COL_MASK);
}

unsigned int hash_whowas_name(char *name)
{
      unsigned char *hname = (unsigned char *)name;
      unsigned int hash = 0;
      int hash2 = 0;
      char lower;

      while (*hname++) {
            lower = ToLower(*hname);
            hash = (hash << 1) + lower;
            hash2 = (hash >> 1) + lower;
      }
      return ((hash & WW_MAX_INITIAL_MASK) << BITS_PER_COL) + (hash2 & BITS_PER_COL_MASK);
}

void clear_client_hash_table()
{
      memset((char *)clientTable, '\0', sizeof(aHashEntry) * U_MAX);
}

void clear_channel_hash_table()
{
      memset((char *)channelTable, '\0', sizeof(aHashEntry) * CH_MAX);
}

int add_to_client_hash_table(char *name, aClient *cptr)
{
      int hashv = hash_nick_name(name);

      SetHashed(cptr);
      cptr->hnext = (aClient *)clientTable[hashv].list;
      clientTable[hashv].list = (void *)cptr;
      clientTable[hashv].links++;
      clientTable[hashv].hits++;
      return 0;
}

int add_to_channel_hash_table(char *name, aChannel *chptr)
{
      int hashv = hash_channel_name(name);

      chptr->hnextch = (aChannel *)channelTable[hashv].list;
      channelTable[hashv].list = (void *)chptr;
      channelTable[hashv].links++;
      channelTable[hashv].hits++;
      return 0;
}

int del_from_client_hash_table(char *name, aClient *cptr)
{
      aClient *tmp, *prev = NULL;
      int hashv = hash_nick_name(name);

      for (tmp = (aClient *)clientTable[hashv].list; tmp != NULL; tmp = tmp->hnext) {
            if (tmp == cptr) {
                  if (prev != NULL) {
                        prev->hnext = tmp->hnext;
                  }
                  else {
                        clientTable[hashv].list = (void *)tmp->hnext;
                  }
                  tmp->hnext = NULL;
                  ClearHashed(tmp);

                  if (clientTable[hashv].links) {
                        clientTable[hashv].links--;
                        return 1;
                  }
                  return -1;
            }
            prev = tmp;
      }
      return 0;
}

int del_from_channel_hash_table(char *name, aChannel *chptr)
{
      aChannel *tmp, *prev = NULL;
      int hashv = hash_channel_name(name);

      for (tmp = (aChannel *)channelTable[hashv].list; tmp != NULL; tmp = tmp->hnextch) {
            if (tmp == chptr) {
                  if (prev != NULL) {
                        prev->hnextch = tmp->hnextch;
                  }
                  else {
                        channelTable[hashv].list = (void *)tmp->hnextch;
                  }
                  tmp->hnextch = NULL;
                  if (channelTable[hashv].links) {
                        channelTable[hashv].links--;
                        return 1;
                  }
                  return -1;
            }
            prev = tmp;
      }
      return 0;
}

aClient *hash_find_client(char *name, aClient *cptr)
{
      aClient *tmp;
      int hashv = hash_nick_name(name);
      aHashEntry *tmp2 = &clientTable[hashv];

      for (tmp = (aClient *)tmp2->list; tmp != NULL; tmp = tmp->hnext) {
            if (!mycmp(name, tmp->name)) {
                  return tmp;
            }
      }
      return cptr;
}

aClient *hash_find_nickserver(char *name, aClient *cptr)
{
      aClient *tmp;
      int hashv = hash_nick_name(name);
      aHashEntry *tmp2 = &clientTable[hashv];
      char *serv = strchr(name, '@');

      *serv++ = '\0';
      for (tmp = (aClient *)tmp2->list; tmp != NULL; tmp = tmp->hnext) {
            if (!mycmp(name, tmp->name) && tmp->user != NULL && !mycmp(serv, tmp->user->server)) {
                  *--serv = '\0';
                  return tmp;
            }
      }
      *--serv = '\0';
      return cptr;
}

aClient *hash_find_server(char *server, aClient *cptr)
{
      aClient *tmp;
      int hashv = hash_nick_name(server);
      aHashEntry *tmp2 = &clientTable[hashv];

      for (tmp = (aClient *)tmp2->list; tmp != NULL; tmp = tmp->hnext) {
            if (!IsServer(tmp) && !IsMe(tmp)) {
                  continue;
            }
            if (!mycmp(server, tmp->name)) {
                  return tmp;
            }
      }
      return cptr;
}

aChannel *hash_find_channel(char *name, aChannel *chptr)
{
      aChannel *tmp;
      int hashv = hash_channel_name(name);
      aHashEntry *tmp2 = &channelTable[hashv];

      for (tmp = (aChannel *)tmp2->list; tmp != NULL; tmp = tmp->hnextch) {
            if (!mycmp(name, tmp->chname)) {
                  return tmp;
            }
      }
      return chptr;
}

void clear_watch_hash_table(void)
{
      memset((char *)watchTable, '\0', sizeof(watchTable));
}

void count_watch_memory(int *count, u_long *memory)
{
      int i = WATCHHASHSIZE;
      aWatch *watch;

      while (i--) {
            for (watch = watchTable[i]; watch != NULL; watch = watch->hnext) {
                  (*count)++;
                  (*memory) += sizeof(aWatch) + strlen(watch->nick);
            }
      }
}

int add_to_watch_hash_table(char *nick, aClient *cptr)
{
      int hashv = hash_nick_name(nick) % WATCHHASHSIZE;
      aWatch *watch;
      SLink *lp;

      if ((watch = watchTable[hashv]) != NULL) {
            while (watch != NULL && mycmp(watch->nick, nick)) {
                  watch = watch->hnext;
            }
      }
      if (watch == NULL) {
            watch = (aWatch *)MyMalloc(sizeof(aWatch) + strlen(nick));
            watch->lasttime = timeofday;
            strcpy(watch->nick, nick);
            watch->watch = NULL;
            watch->hnext = watchTable[hashv];
            watchTable[hashv] = watch;
      }

      if ((lp = watch->watch) != NULL) {
            while (lp != NULL && (lp->value.cptr != cptr)) {
                  lp = lp->next;
            }
      }
      if (lp == NULL) {
            lp = watch->watch;
            watch->watch = make_slink();
            watch->watch->value.cptr = cptr;
            watch->watch->next = lp;

            lp = make_slink();
            lp->next = cptr->user->watch;
            lp->value.wptr = watch;
            cptr->user->watch = lp;
            cptr->user->watches++;
      }
      return 0;
}

int hash_check_watch(aClient *cptr, int reply)
{
      int hashv = hash_nick_name(cptr->name) % WATCHHASHSIZE;
      aWatch *watch;
      SLink *lp;

      if ((watch = watchTable[hashv]) != NULL) {
            while (watch != NULL && mycmp(watch->nick, cptr->name)) {
                  watch = watch->hnext;
            }
      }
      if (watch == NULL) {
            return 0;
      }

      watch->lasttime = timeofday;
      for (lp = watch->watch; lp != NULL; lp = lp->next) {
            send_me_numeric(lp->value.cptr, reply, cptr->name, IsPerson(cptr) ? cptr->username : "<N/A>",
                  IsPerson(cptr) ? MaskedHost(cptr) : "<N/A>", watch->lasttime, cptr->info);
      }
      return 0;
}

aWatch *hash_get_watch(char *name)
{
      int hashv = hash_nick_name(name) % WATCHHASHSIZE;
      aWatch *watch;

      if ((watch = watchTable[hashv]) != NULL) {
            while (watch != NULL && mycmp(watch->nick, name)) {
                  watch = watch->hnext;
            }
      }
      return watch;
}

int del_from_watch_hash_table(char *nick, aClient *cptr)
{
      int hashv = hash_nick_name(nick) % WATCHHASHSIZE;
      aWatch *watch, *wlast = NULL;
      SLink *lp, *last = NULL;

      if ((watch = watchTable[hashv]) != NULL) {
            while (watch != NULL && mycmp(watch->nick, nick)) {
                  wlast = watch;
                  watch = watch->hnext;
            }
      }
      if (watch == NULL) {
            return 0;
      }

      if ((lp = watch->watch) != NULL) {
            while (lp != NULL && lp->value.cptr != cptr) {
                  last = lp;
                  lp = lp->next;
            }
      }
      if (lp == NULL) {
            return 0;
      }

      if (last == NULL) {
            watch->watch = lp->next;
      }
      else {
            last->next = lp->next;
      }
      free_slink(lp);

      last = NULL;
      if ((lp = cptr->user->watch) != NULL) {
            while (lp != NULL && lp->value.wptr != watch) {
                  last = lp;
                  lp = lp->next;
            }
      }
      if (lp == NULL) {
            ircdlog(LOG_ERROR, "del_from_watch_hash_table: watch entry with no client while "
                  "processing nick %s on client %s", nick, cptr->user);
      }
      else {
            if (last == NULL) {
                  cptr->user->watch = lp->next;
            }
            else {
                  last->next = lp->next;
            }
            free_slink(lp);
      }
      if (watch->watch == NULL) {
            if (wlast == NULL) {
                  watchTable[hashv] = watch->hnext;
            }
            else {
                  wlast->hnext = watch->hnext;
            }
            MyFree(watch);
      }
      cptr->user->watches--;
      return 0;
}

int hash_del_watch_list(aClient *cptr)
{
      SLink *np, *lp, *last;
      aWatch *watch;
      int hashv;

      if ((np = cptr->user->watch) == NULL) {
            return 0;
      }

      cptr->user->watch = NULL;
      while (np) {
            watch = np->value.wptr;
            last = NULL;
            for (lp = watch->watch; lp && lp->value.cptr != cptr; lp = lp->next) {
                  last = lp;
            }
            if (lp == NULL) {
                  ircdlog(LOG_ERROR, "hash_del_watch_list: WATCH with no table whilst processing client %s",
                        cptr->name);
            }
            else {
                  if (last == NULL) {
                        watch->watch = lp->next;
                  }
                  else {
                        last->next = lp->next;
                  }
                  free_slink(lp);

                  if (watch->watch == NULL) {
                        aWatch *np2, *nl = NULL;

                        hashv = hash_nick_name(watch->nick) % WATCHHASHSIZE;
                        for (np2 = watchTable[hashv]; np2 != watch; np2 = np2->hnext) {
                              nl = np2;
                        }
                        if (nl != NULL) {
                              nl->hnext = watch->hnext;
                        }
                        else {
                              watchTable[hashv] = watch->hnext;
                        }
                        MyFree(watch);
                  }
            }
            lp = np;
            np = np->next;
            free_slink(lp);
      }
      cptr->user->watches = 0;
      return 0;
}

aChannel *hash_get_chan_bucket(int hashv)
{
      if (hashv > CH_MAX) {
            return NULL;
      }
      return (aChannel *)channelTable[hashv].list;
}

Generated by  Doxygen 1.6.0   Back to index