diff -ruN orig/anope-1.6.2/hostserv.c anope-1.6.2/hostserv.c
--- orig/anope-1.6.2/hostserv.c	2004-04-19 02:36:01.000000000 +0000
+++ anope-1.6.2/hostserv.c	2004-07-20 03:23:20.822824808 +0000
@@ -1050,6 +1050,13 @@
 /*************************************************************************/
 void send_on(char *nick, char *vIdent, char *vhost)
 {
+#ifdef IRC_HYBRID
+    if (vIdent) {
+         send_cmd(ServerName, "CHGIDENT %s %s", nick, vIdent);
+    }
+    send_cmd(ServerName, "SVSMODE %s +h", nick);
+    send_cmd(ServerName, "CHGHOST %s %s", nick, vhost);
+#endif
 #ifdef IRC_UNREAL
     if (vIdent) {
         send_cmd(ServerName, "CHGIDENT %s %s", nick, vIdent);
@@ -1081,6 +1088,10 @@
 /*************************************************************************/
 void send_off(User * u)
 {
+#ifdef IRC_HYBRID
+    send_cmd(ServerName, "SVSMODE %s -h", u->nick);
+    notice_lang(s_HostServ, u, HOST_OFF_HYBRID, u->nick);
+#endif
 #ifdef IRC_UNREAL
     send_cmd(s_HostServ, "SVSMODE %s -xt", u->nick);
     notice_lang(s_HostServ, u, HOST_OFF_UNREAL, u->nick);
diff -ruN orig/anope-1.6.2/hostserv.c.orig anope-1.6.2/hostserv.c.orig
--- orig/anope-1.6.2/hostserv.c.orig	1970-01-01 00:00:00.000000000 +0000
+++ anope-1.6.2/hostserv.c.orig	2004-04-19 02:36:01.000000000 +0000
@@ -0,0 +1,1108 @@
+/* HostServ functions
+ *
+ * (C) 2003 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church. 
+ * 
+ * $Id: hostserv.c 5 2004-03-29 01:29:50Z dane $ 
+ *
+ */
+
+/*************************************************************************/
+#include "services.h"
+#include "pseudo.h"
+
+#define HOST_VERSION 3
+#define HASH(nick)	((tolower((nick)[0])&31)<<5 | (tolower((nick)[1])&31))
+
+void load_hs_dbase_v1(dbFILE * f);
+void load_hs_dbase_v2(dbFILE * f);
+void load_hs_dbase_v3(dbFILE * f);
+
+static int guestnum;            /* Current guest number */
+HostCore *head = NULL;          /* head of the HostCore list */
+HostCore *createHostCorelist(HostCore * next, char *nick, char *vIdent,
+                             char *vHost, char *creator, int32 tmp_time);
+HostCore *findHostCore(HostCore * head, char *nick, boolean * found);
+HostCore *insertHostCore(HostCore * head, HostCore * prev, char *nick,
+                         char *vIdent, char *vHost, char *creator,
+                         int32 tmp_time);
+HostCore *deleteHostCore(HostCore * head, HostCore * prev);
+void delHostCore(char *nick);
+
+static void send_on(char *nick, char *vIdent, char *vhost);
+static void send_off(User * u);
+
+char *getvIdent(char *nick);
+char *getvHost(char *nick);
+
+int is_host_setter(User * u);
+int is_host_remover(User * u);
+
+static int do_help(User * u);
+static int do_set(User * u);
+static int do_on(User * u);
+int do_on_id(User * u);
+static void set_lastmask(User * u);
+static int do_off(User * u);
+static int do_del(User * u);
+static int do_group(User * u);
+static int listOut(User * u);
+int do_hs_sync(NickCore * nc, char *vIdent, char *hostmask, char *creator,
+               time_t time);
+int do_setall(User * u);
+int do_delall(User * u);
+void moduleAddHostServCmds(void);
+/*************************************************************************/
+void moduleAddHostServCmds(void)
+{
+    Command *c;
+    c = createCommand("HELP", do_help, NULL, -1, -1, -1, -1, -1);
+    addCoreCommand(HOSTSERV, c);
+    c = createCommand("SET", do_set, is_host_setter, HOST_HELP_SET, -1, -1,
+                      -1, -1);
+    addCoreCommand(HOSTSERV, c);
+    c = createCommand("GROUP", do_group, NULL, HOST_HELP_GROUP, -1, -1, -1,
+                      -1);
+    addCoreCommand(HOSTSERV, c);
+    c = createCommand("SETALL", do_setall, is_host_setter,
+                      HOST_HELP_SETALL, -1, -1, -1, -1);
+    addCoreCommand(HOSTSERV, c);
+    c = createCommand("DELALL", do_delall, is_host_remover,
+                      HOST_HELP_DELALL, -1, -1, -1, -1);
+    addCoreCommand(HOSTSERV, c);
+    c = createCommand("ON", do_on, NULL, HOST_HELP_ON, -1, -1, -1, -1);
+    addCoreCommand(HOSTSERV, c);
+    c = createCommand("OFF", do_off, NULL, HOST_HELP_OFF, -1, -1, -1, -1);
+    addCoreCommand(HOSTSERV, c);
+    c = createCommand("DEL", do_del, is_host_remover, HOST_HELP_DEL, -1,
+                      -1, -1, -1);
+    addCoreCommand(HOSTSERV, c);
+    c = createCommand("LIST", listOut, is_services_oper, HOST_HELP_LIST,
+                      -1, -1, -1, -1);
+    addCoreCommand(HOSTSERV, c);
+}
+
+/*************************************************************************/
+
+/*************************************************************************/
+/* HostServ initialization. */
+void hostserv_init(void)
+{
+    moduleAddHostServCmds();
+    guestnum = time(NULL);
+    while (guestnum > 9999999)
+        guestnum -= 10000000;
+}
+
+/*************************************************************************/
+/* Main HostServ routine. */
+void hostserv(User * u, char *buf)
+{
+    char *cmd, *s;
+
+    cmd = strtok(buf, " ");
+
+    if (!cmd) {
+        return;
+    } else if (stricmp(cmd, "\1PING") == 0) {
+        if (!(s = strtok(NULL, "")))
+            s = "\1";
+        notice(s_HostServ, u->nick, "\1PING %s", s);
+    } else if (skeleton) {
+        notice_lang(s_HostServ, u, SERVICE_OFFLINE, s_HostServ);
+    } else {
+#ifdef HAS_VHOST
+        mod_run_cmd(s_HostServ, u, HOSTSERV, cmd);
+#else
+        notice_lang(s_HostServ, u, SERVICE_OFFLINE, s_HostServ);
+#endif
+    }
+}
+
+/*************************************************************************/
+/*	Start of Linked List routines					 */
+/*************************************************************************/
+HostCore *createHostCorelist(HostCore * next, char *nick, char *vIdent,
+                             char *vHost, char *creator, int32 tmp_time)
+{
+
+    next = malloc(sizeof(HostCore));
+    if (next == NULL) {
+        wallops(s_HostServ,
+                "Unable to allocate memory to create the vHost LL, problems i sense..");
+    } else {
+        next->nick = malloc(sizeof(char) * strlen(nick) + 1);
+        next->vHost = malloc(sizeof(char) * strlen(vHost) + 1);
+        next->creator = malloc(sizeof(char) * strlen(creator) + 1);
+        if (vIdent)
+            next->vIdent = malloc(sizeof(char) * strlen(vIdent) + 1);
+        if ((next->nick == NULL) || (next->vHost == NULL)
+            || (next->creator == NULL)) {
+            wallops(s_HostServ,
+                    "Unable to allocate memory to create the vHost LL, problems i sense..");
+            return NULL;
+        }
+        strcpy(next->nick, nick);
+        strcpy(next->vHost, vHost);
+        strcpy(next->creator, creator);
+        if (vIdent) {
+            if ((next->vIdent == NULL)) {
+                wallops(s_HostServ,
+                        "Unable to allocate memory to create the vHost LL, problems i sense..");
+                return NULL;
+            }
+            strcpy(next->vIdent, vIdent);
+        } else {
+            next->vIdent = NULL;
+        }
+        next->time = tmp_time;
+        next->next = NULL;
+        return next;
+    }
+    return NULL;
+}
+
+/*************************************************************************/
+/**
+ * Returns either NULL for the head, or the location of the *PREVIOUS*
+ * record, this is where we need to insert etc..
+ *
+ * -rob
+ **/
+HostCore *findHostCore(HostCore * head, char *nick, boolean * found)
+{
+
+    HostCore *previous, *current;
+
+    *found = false;
+    current = head;
+    previous = current;
+
+    while (current != NULL) {
+        if (stricmp(nick, current->nick) == 0) {
+            *found = true;
+            break;
+        } else if (stricmp(nick, current->nick) < 0) {
+            /* we know were not gonna find it now.... */
+            break;
+        } else {
+            previous = current;
+            current = current->next;
+        }
+    }
+    if (current == head) {
+        return NULL;
+    } else {
+        return previous;
+    }
+}
+
+/*************************************************************************/
+HostCore *insertHostCore(HostCore * head, HostCore * prev, char *nick,
+                         char *vIdent, char *vHost, char *creator,
+                         int32 tmp_time)
+{
+
+    HostCore *newCore, *tmp;
+
+    newCore = malloc(sizeof(HostCore));
+    if (newCore == NULL) {
+        wallops(s_HostServ,
+                "Unable to allocate memory to insert into the vHost LL, problems i sense..");
+        return NULL;
+    } else {
+        newCore->nick = malloc(sizeof(char) * strlen(nick) + 1);
+        newCore->vHost = malloc(sizeof(char) * strlen(vHost) + 1);
+        newCore->creator = malloc(sizeof(char) * strlen(creator) + 1);
+        if (vIdent)
+            newCore->vIdent = malloc(sizeof(char) * strlen(vIdent) + 1);
+        if ((newCore->nick == NULL) || (newCore->vHost == NULL)
+            || (newCore->creator == NULL)) {
+            wallops(s_HostServ,
+                    "Unable to allocate memory to create the vHost LL, problems i sense..");
+            return NULL;
+        }
+        strcpy(newCore->nick, nick);
+        strcpy(newCore->vHost, vHost);
+        strcpy(newCore->creator, creator);
+        if (vIdent) {
+            if ((newCore->vIdent == NULL)) {
+                wallops(s_HostServ,
+                        "Unable to allocate memory to create the vHost LL, problems i sense..");
+                return NULL;
+            }
+            strcpy(newCore->vIdent, vIdent);
+        } else {
+            newCore->vIdent = NULL;
+        }
+        newCore->time = tmp_time;
+        if (prev == NULL) {
+            tmp = head;
+            head = newCore;
+            newCore->next = tmp;
+        } else {
+            tmp = prev->next;
+            prev->next = newCore;
+            newCore->next = tmp;
+        }
+    }
+    return head;
+}
+
+/*************************************************************************/
+HostCore *deleteHostCore(HostCore * head, HostCore * prev)
+{
+
+    HostCore *tmp;
+
+    if (prev == NULL) {
+        tmp = head;
+        head = head->next;
+    } else {
+        tmp = prev->next;
+        prev->next = tmp->next;
+    }
+    free(tmp->vHost);
+    free(tmp->nick);
+    free(tmp->creator);
+    if (tmp->vIdent) {
+        free(tmp->vIdent);
+    }
+    free(tmp);
+    return head;
+}
+
+/*************************************************************************/
+void addHostCore(char *nick, char *vIdent, char *vhost, char *creator,
+                 int32 tmp_time)
+{
+    HostCore *tmp;
+    boolean found = false;
+
+    if (head == NULL) {
+        head =
+            createHostCorelist(head, nick, vIdent, vhost, creator,
+                               tmp_time);
+    } else {
+        tmp = findHostCore(head, nick, &found);
+        if (!found) {
+            head =
+                insertHostCore(head, tmp, nick, vIdent, vhost, creator,
+                               tmp_time);
+        } else {
+            head = deleteHostCore(head, tmp);   /* delete the old entry */
+            addHostCore(nick, vIdent, vhost, creator, tmp_time);        /* recursive call to add new entry */
+        }
+    }
+}
+
+/*************************************************************************/
+char *getvHost(char *nick)
+{
+    HostCore *tmp;
+    boolean found = false;
+    tmp = findHostCore(head, nick, &found);
+    if (found) {
+        if (tmp == NULL)
+            return head->vHost;
+        else
+            return tmp->next->vHost;
+    }
+    return NULL;
+}
+
+/*************************************************************************/
+char *getvIdent(char *nick)
+{
+    HostCore *tmp;
+    boolean found = false;
+    tmp = findHostCore(head, nick, &found);
+    if (found) {
+        if (tmp == NULL)
+            return head->vIdent;
+        else
+            return tmp->next->vIdent;
+    }
+    return NULL;
+}
+
+/*************************************************************************/
+int listOut(User * u)
+{
+    char *key = strtok(NULL, "");
+    struct tm *tm;
+    char buf[BUFSIZE];
+    int counter = 1;
+    int from = 0, to = 0;
+    char *tmp = NULL;
+    char *s = NULL;
+    int display_counter = 0;
+
+    HostCore *current;
+
+    current = head;
+    if (current == NULL)
+        notice_lang(s_HostServ, u, HOST_EMPTY);
+    else {
+                /**
+		 * Do a check for a range here, then in the next loop
+		 * we'll only display what has been requested..
+		 **/
+        if (key) {
+            if (key[0] == '#') {
+                tmp = myStrGetOnlyToken((key + 1), '-', 0);     /* Read FROM out */
+                if (!tmp) {
+                    return MOD_CONT;
+                }
+                for (s = tmp; *s; s++) {
+                    if (!isdigit(*s)) {
+                        return MOD_CONT;
+                    }
+                }
+                from = atoi(tmp);
+                tmp = myStrGetTokenRemainder(key, '-', 1);      /* Read TO out */
+                if (!tmp) {
+                    return MOD_CONT;
+                }
+                for (s = tmp; *s; s++) {
+                    if (!isdigit(*s)) {
+                        return MOD_CONT;
+                    }
+                }
+                to = atoi(tmp);
+                key = NULL;
+            }
+        }
+
+        while (current != NULL) {
+            if (key) {
+                if (((match_wild_nocase(key, current->nick))
+                     || (match_wild_nocase(key, current->vHost)))
+                    && (display_counter < NSListMax)) {
+                    display_counter++;
+                    tm = localtime(&current->time);
+                    strftime(buf, sizeof(buf),
+                             getstring(NULL,
+                                       STRFTIME_DATE_TIME_FORMAT), tm);
+                    if (current->vIdent) {
+                        notice_lang(s_HostServ, u, HOST_IDENT_ENTRY,
+                                    counter, current->nick,
+                                    current->vIdent, current->vHost,
+                                    current->creator, buf);
+                    } else {
+                        notice_lang(s_HostServ, u, HOST_ENTRY, counter,
+                                    current->nick, current->vHost,
+                                    current->creator, buf);
+                    }
+                }
+            } else {
+                        /**
+			 * List the host if its in the display range, and not more
+			 * than NSListMax records have been displayed...
+			 **/
+                if ((((counter >= from) && (counter <= to))
+                     || ((from == 0) && (to == 0)))
+                    && (display_counter < NSListMax)) {
+                    display_counter++;
+                    tm = localtime(&current->time);
+                    strftime(buf, sizeof(buf),
+                             getstring(NULL, STRFTIME_DATE_TIME_FORMAT),
+                             tm);
+                    if (current->vIdent) {
+                        notice_lang(s_HostServ, u, HOST_IDENT_ENTRY,
+                                    counter, current->nick,
+                                    current->vIdent, current->vHost,
+                                    current->creator, buf);
+                    } else {
+                        notice_lang(s_HostServ, u, HOST_ENTRY, counter,
+                                    current->nick, current->vHost,
+                                    current->creator, buf);
+                    }
+                }
+            }
+            counter++;
+            current = current->next;
+        }
+        if (key) {
+            notice_lang(s_HostServ, u, HOST_LIST_KEY_FOOTER, key,
+                        display_counter);
+        } else {
+            if (from != 0) {
+                notice_lang(s_HostServ, u, HOST_LIST_RANGE_FOOTER, from,
+                            to);
+            } else {
+                notice_lang(s_HostServ, u, HOST_LIST_FOOTER,
+                            display_counter);
+            }
+        }
+    }
+    return MOD_CONT;
+}
+
+/*************************************************************************/
+void delHostCore(char *nick)
+{
+#ifdef USE_RDB
+    static char clause[128];
+#endif
+    HostCore *tmp;
+    boolean found = false;
+    tmp = findHostCore(head, nick, &found);
+    if (found) {
+        head = deleteHostCore(head, tmp);
+
+#ifdef USE_RDB
+        /* Reflect this change in the database right away. */
+        if (rdb_open()) {
+
+            snprintf(clause, sizeof(clause), "nick='%s'", nick);
+            rdb_scrub_table("anope_hs_core", clause);
+            rdb_close();
+        }
+#endif
+
+    }
+
+}
+
+/*************************************************************************/
+/*	End of Linked List routines					 */
+/*************************************************************************/
+/*************************************************************************/
+/*	Start of Load/Save routines					 */
+/*************************************************************************/
+#define SAFE(x) do {					\
+    if ((x) < 0) {					\
+	if (!forceload)					\
+	    fatal("Read error on %s", HostDBName);	\
+	failed = 1;					\
+	break;						\
+    }							\
+} while (0)
+
+void load_hs_dbase(void)
+{
+    dbFILE *f;
+    int ver;
+
+    if (!(f = open_db(s_HostServ, HostDBName, "r", HOST_VERSION))) {
+        return;
+    }
+    ver = get_file_version(f);
+
+    if (ver == 1) {
+        load_hs_dbase_v1(f);
+    } else if (ver == 2) {
+        load_hs_dbase_v2(f);
+    } else if (ver == 3) {
+        load_hs_dbase_v3(f);
+    }
+    close_db(f);
+}
+
+void load_hs_dbase_v1(dbFILE * f)
+{
+    int c;
+    int failed = 0;
+    int32 tmp;
+
+    char *nick;
+    char *vHost;
+
+    tmp = time(NULL);
+
+    alog("Attempting to load V1 HS Database");
+    while (!failed && (c = getc_db(f)) == 1) {
+
+        if (c == 1) {
+            SAFE(read_string(&nick, f));
+            SAFE(read_string(&vHost, f));
+            addHostCore(nick, NULL, vHost, "Unknown", tmp);     /* could get a speed increase by not searching the list */
+            free(nick);         /* as we know the db is in alphabetical order... */
+            free(vHost);
+        } else {
+            fatal("Invalid format in %s %d", HostDBName, c);
+        }
+    }
+}
+
+void load_hs_dbase_v2(dbFILE * f)
+{
+    int c;
+    int failed = 0;
+
+    char *nick;
+    char *vHost;
+    char *creator;
+    int32 time;
+
+    alog("Attempting to load V2 HS Database");
+    while (!failed && (c = getc_db(f)) == 1) {
+
+        if (c == 1) {
+            SAFE(read_string(&nick, f));
+            SAFE(read_string(&vHost, f));
+            SAFE(read_string(&creator, f));
+            SAFE(read_int32(&time, f));
+            addHostCore(nick, NULL, vHost, creator, time);      /* could get a speed increase by not searching the list */
+            free(nick);         /* as we know the db is in alphabetical order... */
+            free(vHost);
+            free(creator);
+        } else {
+            fatal("Invalid format in %s %d", HostDBName, c);
+        }
+    }
+}
+
+void load_hs_dbase_v3(dbFILE * f)
+{
+    int c;
+    int failed = 0;
+
+    char *nick;
+    char *vHost;
+    char *creator;
+    char *vIdent;
+    int32 time;
+
+    alog("Attempting to load V3 HS Database");
+    while (!failed && (c = getc_db(f)) == 1) {
+        if (c == 1) {
+            SAFE(read_string(&nick, f));
+            SAFE(read_string(&vIdent, f));
+            SAFE(read_string(&vHost, f));
+            SAFE(read_string(&creator, f));
+            SAFE(read_int32(&time, f));
+            addHostCore(nick, vIdent, vHost, creator, time);    /* could get a speed increase by not searching the list */
+            free(nick);         /* as we know the db is in alphabetical order... */
+            free(vHost);
+            free(creator);
+            free(vIdent);
+        } else {
+            fatal("Invalid format in %s %d", HostDBName, c);
+        }
+    }
+}
+
+#undef SAFE
+/*************************************************************************/
+#define SAFE(x) do {						\
+    if ((x) < 0) {						\
+	restore_db(f);						\
+	log_perror("Write error on %s", HostDBName);		\
+	if (time(NULL) - lastwarn > WarningTimeout) {		\
+	    wallops(NULL, "Write error on %s: %s", HostDBName,	\
+			strerror(errno));			\
+	    lastwarn = time(NULL);				\
+	}							\
+	return;							\
+    }								\
+} while (0)
+
+void save_hs_dbase(void)
+{
+    dbFILE *f;
+    static time_t lastwarn = 0;
+    HostCore *current;
+
+    if (!(f = open_db(s_HostServ, HostDBName, "w", HOST_VERSION)))
+        return;
+
+    current = head;
+    while (current != NULL) {
+        SAFE(write_int8(1, f));
+        SAFE(write_string(current->nick, f));
+        SAFE(write_string(current->vIdent, f));
+        SAFE(write_string(current->vHost, f));
+        SAFE(write_string(current->creator, f));
+        SAFE(write_int32(current->time, f));
+        current = current->next;
+    }
+    SAFE(write_int8(0, f));
+    close_db(f);
+
+}
+
+#undef SAFE
+
+void save_hs_rdb_dbase(void)
+{
+#ifdef USE_RDB
+    HostCore *current;
+
+    if (!rdb_open())
+        return;
+
+    rdb_clear_table("anope_hs_core");
+
+    current = head;
+    while (current != NULL) {
+        rdb_save_hs_core(current);
+        current = current->next;
+    }
+    rdb_close();
+#endif
+}
+
+/*************************************************************************/
+/*	End of Load/Save Functions					 */
+/*************************************************************************/
+/*************************************************************************/
+/*	Start of Generic Functions					 */
+/*************************************************************************/
+int do_setall(User * u)
+{
+
+    char *nick = strtok(NULL, " ");
+    char *rawhostmask = strtok(NULL, " ");
+    char *hostmask = smalloc(HOSTMAX);
+
+    NickAlias *na;
+    int32 tmp_time;
+    char *s;
+
+    char *vIdent = NULL;
+
+    if (!nick || !rawhostmask) {
+        notice_lang(s_HostServ, u, HOST_SETALL_SYNTAX, s_HostServ);
+        return MOD_CONT;
+    }
+
+    vIdent = myStrGetOnlyToken(rawhostmask, '@', 0);    /* Get the first substring, @ as delimiter */
+    if (vIdent) {
+        rawhostmask = myStrGetTokenRemainder(rawhostmask, '@', 1);      /* get the remaining string */
+        if (!rawhostmask) {
+            notice_lang(s_HostServ, u, HOST_SETALL_SYNTAX, s_HostServ);
+            return MOD_CONT;
+        }
+        if (strlen(vIdent) > USERMAX - 1) {
+            notice_lang(s_HostServ, u, HOST_SET_IDENTTOOLONG, USERMAX);
+            return MOD_CONT;
+        } else {
+            for (s = vIdent; *s; s++) {
+                if (!isvalidchar(*s)) {
+                    notice_lang(s_HostServ, u, HOST_SET_IDENT_ERROR);
+                    return MOD_CONT;
+                }
+            }
+        }
+#ifndef HAS_VIDENT
+        notice_lang(s_HostServ, u, HOST_NO_VIDENT);
+        return MOD_CONT;
+#endif
+    }
+
+    if (strlen(rawhostmask) < HOSTMAX - 1)
+        snprintf(hostmask, HOSTMAX - 1, "%s", rawhostmask);
+    else {
+        notice_lang(s_HostServ, u, HOST_SET_TOOLONG, HOSTMAX);
+        return MOD_CONT;
+    }
+
+    if (!isValidHost(hostmask, 3)) {
+        notice_lang(s_HostServ, u, HOST_SET_ERROR);
+        return MOD_CONT;
+    }
+
+    tmp_time = time(NULL);
+
+    if ((na = findnick(nick))) {
+        alog("vHost for all nicks in group \002%s\002 set to \002%s\002 by oper \002%s\002", nick, hostmask, u->nick);
+        do_hs_sync(na->nc, vIdent, hostmask, u->nick, tmp_time);
+        if (vIdent) {
+            notice_lang(s_HostServ, u, HOST_IDENT_SETALL, nick, vIdent,
+                        hostmask);
+        } else {
+            notice_lang(s_HostServ, u, HOST_SETALL, nick, hostmask);
+        }
+    } else {
+        notice_lang(s_HostServ, u, HOST_NOREG, nick);
+    }
+
+    free(hostmask);
+    return MOD_CONT;
+}
+
+int do_delall(User * u)
+{
+    int i;
+    char *nick = strtok(NULL, " ");
+    NickAlias *na;
+    NickCore *nc;
+    if (!nick) {
+        notice_lang(s_HostServ, u, HOST_DELALL_SYNTAX, s_HostServ);
+        return MOD_CONT;
+    }
+    if ((na = findnick(nick))) {
+        nc = na->nc;
+        for (i = 0; i < nc->aliases.count; i++) {
+            na = nc->aliases.list[i];
+            delHostCore(na->nick);
+        }
+        alog("vHosts for all nicks in group \002%s\002 deleted by oper \002%s\002", nc->display, u->nick);
+        notice_lang(s_HostServ, u, HOST_DELALL, nc->display);
+    } else {
+        notice_lang(s_HostServ, u, HOST_NOREG, nick);
+    }
+    return MOD_CONT;
+}
+
+int do_hs_sync(NickCore * nc, char *vIdent, char *hostmask, char *creator,
+               time_t time)
+{
+    int i;
+    NickAlias *na;
+
+    for (i = 0; i < nc->aliases.count; i++) {
+        na = nc->aliases.list[i];
+        addHostCore(na->nick, vIdent, hostmask, creator, time);
+    }
+    return MOD_CONT;
+}
+
+static int do_group(User * u)
+{
+    NickAlias *na;
+    HostCore *tmp;
+    char *vHost = NULL;
+    char *vIdent = NULL;
+    char *creator = NULL;
+    time_t time;
+    boolean found = false;
+
+    if ((na = findnick(u->nick))) {
+        if (na->status & NS_IDENTIFIED) {
+            tmp = findHostCore(head, u->nick, &found);
+            if (found) {
+                if (tmp == NULL) {
+                    tmp = head; /* incase first in list */
+                } else if (tmp->next) { /* we dont want the previous entry were not inserting! */
+                    tmp = tmp->next;    /* jump to the next */
+                }
+
+                vHost = sstrdup(tmp->vHost);
+                if (tmp->vIdent)
+                    vIdent = sstrdup(tmp->vIdent);
+                creator = sstrdup(tmp->creator);
+                time = tmp->time;
+
+                do_hs_sync(na->nc, vIdent, vHost, creator, time);
+                if (tmp->vIdent) {
+                    notice_lang(s_HostServ, u, HOST_IDENT_GROUP,
+                                na->nc->display, vIdent, vHost);
+                } else {
+                    notice_lang(s_HostServ, u, HOST_GROUP, na->nc->display,
+                                vHost);
+                }
+                free(vHost);
+                if (vIdent)
+                    free(vIdent);
+                free(creator);
+
+            } else {
+                notice_lang(s_HostServ, u, HOST_NOT_ASSIGNED);
+            }
+        } else {
+            notice_lang(s_HostServ, u, HOST_ID);
+        }
+    } else {
+        notice_lang(s_HostServ, u, HOST_NOT_REGED);
+    }
+    return MOD_CONT;
+}
+
+static int do_help(User * u)
+{
+    char *cmd = strtok(NULL, "");
+
+    if (!cmd) {
+        notice_help(s_HostServ, u, HOST_HELP, s_HostServ);
+        if ((is_services_oper(u)) || (is_host_setter(u)))
+            notice_help(s_HostServ, u, HOST_OPER_HELP);
+        if (is_services_admin(u))
+            notice_help(s_HostServ, u, HOST_ADMIN_HELP);
+        moduleDisplayHelp(6, u);
+    } else {
+        mod_help_cmd(s_HostServ, u, HOSTSERV, cmd);
+    }
+    return MOD_CONT;
+}
+
+/*************************************************************************/
+int do_set(User * u)
+{
+    char *nick = strtok(NULL, " ");
+    char *rawhostmask = strtok(NULL, " ");
+    char *hostmask = smalloc(HOSTMAX);
+
+    NickAlias *na;
+    int32 tmp_time;
+    char *s;
+
+    char *vIdent = NULL;
+
+    if (!nick || !rawhostmask) {
+        notice_lang(s_HostServ, u, HOST_SET_SYNTAX, s_HostServ);
+        return MOD_CONT;
+    }
+
+    vIdent = myStrGetOnlyToken(rawhostmask, '@', 0);    /* Get the first substring, @ as delimiter */
+    if (vIdent) {
+        rawhostmask = myStrGetTokenRemainder(rawhostmask, '@', 1);      /* get the remaining string */
+        if (!rawhostmask) {
+            notice_lang(s_HostServ, u, HOST_SET_SYNTAX, s_HostServ);
+            return MOD_CONT;
+        }
+        if (strlen(vIdent) > USERMAX - 1) {
+            notice_lang(s_HostServ, u, HOST_SET_IDENTTOOLONG, USERMAX);
+            return MOD_CONT;
+        } else {
+            for (s = vIdent; *s; s++) {
+                if (!isvalidchar(*s)) {
+                    notice_lang(s_HostServ, u, HOST_SET_IDENT_ERROR);
+                    return MOD_CONT;
+                }
+            }
+        }
+#ifndef HAS_VIDENT
+        notice_lang(s_HostServ, u, HOST_NO_VIDENT);
+        return MOD_CONT;
+#endif
+    }
+    if (strlen(rawhostmask) < HOSTMAX - 1)
+        snprintf(hostmask, HOSTMAX - 1, "%s", rawhostmask);
+    else {
+        notice_lang(s_HostServ, u, HOST_SET_TOOLONG, HOSTMAX);
+        return MOD_CONT;
+    }
+
+    if (!isValidHost(hostmask, 3)) {
+        notice_lang(s_HostServ, u, HOST_SET_ERROR);
+        return MOD_CONT;
+    }
+
+
+    tmp_time = time(NULL);
+
+    if ((na = findnick(nick))) {
+        alog("vHost for user \002%s\002 set to \002%s\002 by oper \002%s\002", nick, hostmask, u->nick);
+        addHostCore(nick, vIdent, hostmask, u->nick, tmp_time);
+        if (vIdent) {
+            notice_lang(s_HostServ, u, HOST_IDENT_SET, nick, vIdent,
+                        hostmask);
+        } else {
+            notice_lang(s_HostServ, u, HOST_SET, nick, hostmask);
+        }
+    } else {
+        notice_lang(s_HostServ, u, HOST_NOREG, nick);
+    }
+    free(hostmask);
+    return MOD_CONT;
+}
+
+/*************************************************************************/
+int do_on(User * u)
+{
+    NickAlias *na;
+    char *vHost;
+    char *vIdent = NULL;
+    if ((na = findnick(u->nick))) {
+        if (na->status & NS_IDENTIFIED) {
+            vHost = getvHost(u->nick);
+            vIdent = getvIdent(u->nick);
+            if (vHost == NULL) {
+                notice_lang(s_HostServ, u, HOST_NOT_ASSIGNED);
+            } else {
+                if (vIdent) {
+                    notice_lang(s_HostServ, u, HOST_IDENT_ACTIVATED,
+                                vIdent, vHost);
+                } else {
+                    notice_lang(s_HostServ, u, HOST_ACTIVATED, vHost);
+                }
+                send_on(u->nick, vIdent, vHost);
+#ifdef HAS_VHOST
+                u->vhost = sstrdup(vHost);
+#endif
+#ifdef HAS_VIDENT
+                if (vIdent)
+                    u->vident = sstrdup(vIdent);
+#endif
+                set_lastmask(u);
+            }
+        } else {
+            notice_lang(s_HostServ, u, HOST_ID);
+        }
+    } else {
+        notice_lang(s_HostServ, u, HOST_NOT_REGED);
+    }
+    return MOD_CONT;
+}
+
+/*************************************************************************/
+int do_on_id(User * u)
+{                               /* we've assumed that the user exists etc.. */
+    char *vHost;                /* as were only gonna call this from nsid routine */
+    char *vIdent;
+    vHost = getvHost(u->nick);
+    vIdent = getvIdent(u->nick);
+    if (vHost != NULL) {
+        if (vIdent) {
+            notice_lang(s_HostServ, u, HOST_IDENT_ACTIVATED, vIdent,
+                        vHost);
+        } else {
+            notice_lang(s_HostServ, u, HOST_ACTIVATED, vHost);
+        }
+        send_on(u->nick, vIdent, vHost);
+#ifdef HAS_VHOST
+        u->vhost = sstrdup(vHost);
+#endif
+#ifdef HAS_VIDENT
+        if (vIdent)
+            u->vident = sstrdup(vIdent);
+#endif
+        set_lastmask(u);
+    }
+    return MOD_CONT;
+}
+
+/*************************************************************************/
+int do_del(User * u)
+{
+    NickAlias *na;
+    char *nick = strtok(NULL, " ");
+    if (nick) {
+        if ((na = findnick(nick))) {
+            alog("vHost for user \002%s\002 deleted by oper \002%s\002",
+                 nick, u->nick);
+            delHostCore(nick);
+            notice_lang(s_HostServ, u, HOST_DEL, nick);
+        } else {
+            notice_lang(s_HostServ, u, HOST_NOREG, nick);
+        }
+    } else {
+        notice_lang(s_HostServ, u, HOST_DEL_SYNTAX, s_HostServ);
+    }
+    return MOD_CONT;
+}
+
+/*************************************************************************/
+int do_off(User * u)
+{
+    /* put any generic code here... :) */
+    send_off(u);
+    return MOD_CONT;
+}
+
+int is_host_setter(User * u)
+{
+    int i, j;
+    NickAlias *na;
+
+    if (is_services_oper(u)) {
+        return 1;
+    }
+    if (!nick_identified(u)) {
+        return 0;
+    }
+
+    /* Look through all user's aliases (0000412) */
+    for (i = 0; i < u->na->nc->aliases.count; i++) {
+        na = u->na->nc->aliases.list[i];
+        for (j = 0; j < HostNumber; j++) {
+            if (stricmp(HostSetters[j], na->nick) == 0) {
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+int is_host_remover(User * u)
+{
+    return is_host_setter(u);   /* only here incase we want to split them up later */
+}
+
+/*
+ * Sets the last_usermak properly. Using virtual ident and/or host 
+ */
+void set_lastmask(User * u)
+{
+    if (u->na->last_usermask)
+        free(u->na->last_usermask);
+
+    u->na->last_usermask =
+        smalloc(strlen(GetIdent(u)) + strlen(GetHost(u)) + 2);
+    sprintf(u->na->last_usermask, "%s@%s", GetIdent(u), GetHost(u));
+
+}
+
+/*************************************************************************/
+/*	End of Generic Functions					 */
+/*************************************************************************/
+/*************************************************************************/
+/*	Start of Server Functions					 */
+/*************************************************************************/
+void send_on(char *nick, char *vIdent, char *vhost)
+{
+#ifdef IRC_UNREAL
+    if (vIdent) {
+        send_cmd(ServerName, "CHGIDENT %s %s", nick, vIdent);
+    }
+    send_cmd(ServerName, "CHGHOST %s %s", nick, vhost);
+#endif
+#ifdef IRC_VIAGRA
+    if (vIdent) {
+        send_cmd(NULL, "CHGIDENT %s %s", nick, vIdent);
+    }
+    send_cmd(NULL, "SVSMODE %s +x", nick);
+    send_cmd(NULL, "SVSCHGHOST %s %s", nick, vhost);
+#endif
+#ifdef IRC_ULTIMATE
+    if (vIdent) {
+        send_cmd(ServerName, "CHGIDENT %s %s", nick, vIdent);
+    }
+    send_cmd(s_HostServ, "SVSMODE %s +x", nick);
+    send_cmd(ServerName, "CHGHOST %s %s", nick, vhost);
+#endif
+#ifdef IRC_ULTIMATE3
+    send_cmd(s_HostServ, "SVSMODE %s +x", nick);
+    send_cmd(ServerName, "SETHOST %s %s", nick, vhost);
+#endif
+
+
+}
+
+/*************************************************************************/
+void send_off(User * u)
+{
+#ifdef IRC_UNREAL
+    send_cmd(s_HostServ, "SVSMODE %s -xt", u->nick);
+    notice_lang(s_HostServ, u, HOST_OFF_UNREAL, u->nick);
+    /*
+     * tell them to type /mode nick +x to get their original
+     * host cloaking back
+     */
+#endif
+#ifdef IRC_VIAGRA
+    send_cmd(NULL, "SVSMODE %s -x", u->nick);
+    notice_lang(s_HostServ, u, HOST_OFF_UNREAL, u->nick);
+#endif
+#ifdef IRC_ULTIMATE
+    /* UltimateIRCd 2.x does not allow users to control +x */
+#endif
+#ifdef IRC_ULTIMATE3
+    send_cmd(s_HostServ, "SVSMODE %s -x", u->nick);
+    notice_lang(s_HostServ, u, HOST_OFF_UNREAL, u->nick);
+#endif
+
+}
+
+/*************************************************************************/
+/*	End of Server Functions						 */
+/*************************************************************************/
diff -ruN orig/anope-1.6.2/lang/en_us.l anope-1.6.2/lang/en_us.l
--- orig/anope-1.6.2/lang/en_us.l	2004-04-19 02:36:02.000000000 +0000
+++ anope-1.6.2/lang/en_us.l	2004-07-20 03:24:54.024655976 +0000
@@ -5831,6 +5831,8 @@
 	Syntax: /msg %s del <nick>.
 HOST_OFF_UNREAL
 	Your vhost was removed. To re-enable the standard host cloaking, type /mode %s +x
+HOST_OFF_HYBRID
+	Your vhost was removed. To re-enable the standard host cloaking, type /mode %s +h
 HOST_NO_VIDENT
 	Your IRCD does not support vIdent's, if this is incorrect, please report this as a possible bug
 HOST_GROUP
diff -ruN orig/anope-1.6.2/lang/index anope-1.6.2/lang/index
--- orig/anope-1.6.2/lang/index	2004-04-19 02:36:02.000000000 +0000
+++ anope-1.6.2/lang/index	2004-07-20 03:25:12.046916176 +0000
@@ -1391,6 +1391,7 @@
 HOST_DEL
 HOST_DEL_SYNTAX
 HOST_OFF_UNREAL
+HOST_OFF_HYBRID
 HOST_NO_VIDENT
 HOST_GROUP
 HOST_IDENT_GROUP
Files orig/anope-1.6.2/modules/hs_moo.o and anope-1.6.2/modules/hs_moo.o differ
Files orig/anope-1.6.2/modules/ircd_catserv.o and anope-1.6.2/modules/ircd_catserv.o differ
diff -ruN orig/anope-1.6.2/services.h anope-1.6.2/services.h
--- orig/anope-1.6.2/services.h	2004-04-19 02:36:01.000000000 +0000
+++ anope-1.6.2/services.h	2004-07-20 01:21:49.000000000 +0000
@@ -130,6 +130,7 @@
 /* Protocol tweaks */
 #ifdef IRC_HYBRID
 # define HAS_HALFOP
+# define HAS_VHOST
 #endif
 
 #ifdef IRC_VIAGRA
diff -ruN orig/anope-1.6.2/services.h.orig anope-1.6.2/services.h.orig
--- orig/anope-1.6.2/services.h.orig	1970-01-01 00:00:00.000000000 +0000
+++ anope-1.6.2/services.h.orig	2004-04-19 02:36:01.000000000 +0000
@@ -0,0 +1,1198 @@
+/*
+ *
+ * (C) 2003 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church. 
+ * 
+ *
+ */
+
+#ifndef SERVICES_H
+#define SERVICES_H
+
+/*************************************************************************/
+
+#include "sysconf.h"
+#include "config.h"
+
+/* Some Linux boxes (or maybe glibc includes) require this for the
+ * prototype of strsignal(). */
+#define _GNU_SOURCE
+
+/* Some AIX boxes define int16 and int32 on their own.  Blarph. */
+#if INTTYPE_WORKAROUND
+# define int16 builtin_int16
+# define int32 builtin_int32
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/stat.h>	/* for umask() on some systems */
+#include <sys/types.h>
+#include <sys/time.h>
+
+#ifdef USE_RDB
+# define MAX_SQL_BUF   4096
+#endif
+
+#ifdef USE_MYSQL
+# define MYSQL_WARNING 2
+# define MYSQL_ERROR   4
+#ifdef HAVE_MYSQL_MYSQL_H
+# include <mysql.h>
+# include <errmsg.h>
+#else
+# include <mysql/mysql.h>
+# include <mysql/errmsg.h>
+#endif
+#endif
+
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#if HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+#ifdef USE_THREADS
+# include <pthread.h>
+#endif
+
+#ifdef _AIX
+/* Some AIX boxes seem to have bogus includes that don't have these
+ * prototypes. */
+extern int strcasecmp(const char *, const char *);
+extern int strncasecmp(const char *, const char *, size_t);
+# if 0	/* These break on some AIX boxes (4.3.1 reported). */
+extern int gettimeofday(struct timeval *, struct timezone *);
+extern int socket(int, int, int);
+extern int bind(int, struct sockaddr *, int);
+extern int connect(int, struct sockaddr *, int);
+extern int shutdown(int, int);
+# endif
+# undef FD_ZERO
+# define FD_ZERO(p) memset((p), 0, sizeof(*(p)))
+#endif /* _AIX */
+
+/* Alias stricmp/strnicmp to strcasecmp/strncasecmp if we have the latter
+ * but not the former. */
+#if !HAVE_STRICMP && HAVE_STRCASECMP
+# define stricmp strcasecmp
+# define strnicmp strncasecmp
+#endif
+
+/* We have our own versions of toupper()/tolower(). */
+#include <ctype.h>
+#undef tolower
+#undef toupper
+#define tolower tolower_
+#define toupper toupper_
+extern int toupper(char), tolower(char);
+
+/* We also have our own encrypt(). */
+#define encrypt encrypt_
+
+
+#if INTTYPE_WORKAROUND
+# undef int16
+# undef int32
+#endif
+
+
+/* Miscellaneous definitions. */
+#include "defs.h"
+#include "slist.h"
+
+/*************************************************************************/
+
+typedef struct user_ User;
+typedef struct channel_ Channel;
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Protocol tweaks */
+#ifdef IRC_HYBRID
+# define HAS_HALFOP
+#endif
+
+#ifdef IRC_VIAGRA
+# define HAS_HALFOP
+# define HAS_VHOST
+# define HAS_VIDENT
+#endif
+
+#ifdef IRC_BAHAMUT
+# define HAS_NICKIP
+#endif
+
+#ifdef IRC_PTLINK
+# define HAS_NICKVHOST
+# define HAS_VHOST
+# define HAS_FMODE
+#endif
+
+#ifdef IRC_ULTIMATE
+# define HAS_FMODE			/* Has +f chan mode */
+# define HAS_HALFOP
+# define HAS_LMODE			/* Has +L chan mode */
+# define HAS_VHOST
+# define HAS_VIDENT			/* Can the IRCD Change Idents on the fly */
+#endif
+
+#ifdef IRC_UNREAL
+# define HAS_FMODE			/* Has +f chan mode */
+# define HAS_HALFOP
+# define HAS_LMODE			/* Has +L chan mode */
+# define HAS_NICKVHOST
+# define HAS_VHOST
+# define HAS_VIDENT			/* Can the IRCD Change Idents on the fly */
+#endif
+
+#ifdef IRC_ULTIMATE3
+# define HAS_HALFOP
+# define HAS_VHOST
+# define HAS_NICKVHOST
+# define HAS_VIDENT			/* Can the IRCD Change Idents on the fly */
+#endif
+
+/*************************************************************************/
+
+/* File version for each database. Was one version for all before but was
+   changed so they are now easier to maintain. =) */
+
+#define BOT_VERSION 		10
+#define CHAN_VERSION 		16
+#define EXCEPTION_VERSION 	9
+#define NEWS_VERSION 		9
+#define NICK_VERSION 		13
+#define PRE_NICK_VERSION 	1
+#define OPER_VERSION 		13
+
+typedef enum { false, true } boolean;
+
+/*************************************************************************/
+
+/* Memo info structures.  Since both nicknames and channels can have memos,
+ * we encapsulate memo data in a MemoList to make it easier to handle. */
+
+typedef struct memo_ Memo;
+struct memo_ {
+    uint32 number;	/* Index number -- not necessarily array position! */
+    int16 flags;
+    time_t time;	/* When it was sent */
+    char sender[NICKMAX];
+    char *text;
+};
+
+#define MF_UNREAD	0x0001	/* Memo has not yet been read */
+
+typedef struct {
+    int16 memocount, memomax;
+    Memo *memos;
+} MemoInfo;
+
+/*************************************************************************/
+
+/* NickServ nickname structures. */
+typedef struct nickrequest_ NickRequest;
+typedef struct nickalias_ NickAlias;
+typedef struct nickcore_ NickCore;
+
+struct nickrequest_ {
+	NickRequest *next, *prev;
+	char *nick;
+	char *passcode;
+	char *password;
+	char *email;
+	time_t requested;
+
+	time_t lastmail;			/* Unsaved */
+};
+
+struct nickalias_ {
+	NickAlias *next, *prev;
+
+	char *nick;						/* Nickname */
+
+	char *last_quit;				/* Last quit message */
+	char *last_realname;			/* Last realname */
+	char *last_usermask;			/* Last usermask */
+
+    time_t time_registered;			/* When the nick was registered */
+    time_t last_seen;				/* When it was seen online for the last time */
+
+    int16 status;					/* See NS_* below */
+
+    NickCore *nc;					/* I'm an alias of this */
+
+    /* Not saved */
+    User *u;						/* Current online user that has me */
+};
+
+struct nickcore_ {
+	NickCore *next, *prev;
+
+	char *display;					/* How the nick is displayed */
+	char *pass;						/* Password of the nicks */
+
+	char *email;					/* E-mail associated to the nick */
+	char *greet;					/* Greet associated to the nick */
+	uint32 icq;						/* ICQ # associated to the nick */
+	char *url;						/* URL associated to the nick */
+
+	int32 flags;					/* See NI_* below */
+	uint16 language;				/* Language selected by nickname owner (LANG_*) */
+
+    int16 accesscount;				/* # of entries */
+    char **access;					/* Array of strings */
+
+    MemoInfo memos;
+
+    uint16 channelcount;			/* Number of channels currently registered */
+    uint16 channelmax;				/* Maximum number of channels allowed */
+
+    /* Unsaved data */
+
+    time_t lastmail;				/* Last time this nick record got a mail */
+    SList aliases;					/* List of aliases */
+};
+
+/* Nickname status flags: */
+#define NS_VERBOTEN		0x0002  	/* Nick may not be registered or used */
+#define NS_NO_EXPIRE	0x0004      /* Nick never expires */
+#define NS_IDENTIFIED	0x8000      /* User has IDENTIFY'd */
+#define NS_RECOGNIZED	0x4000      /* ON_ACCESS true && SECURE flag not set */
+#define NS_ON_ACCESS	0x2000      /* User comes from a known address */
+#define NS_KILL_HELD	0x1000      /* Nick is being held after a kill */
+#define NS_GUESTED	    0x0100	    /* SVSNICK has been sent but nick has not
+				     				 * yet changed. An enforcer will be
+				     				 * introduced when it does change. */
+#define NS_MASTER		0x0200		/* Was a master nick; used to import old databases */
+#define NS_TRANSGROUP	0xC000		/* Status flags that can be passed to a nick of the
+									   same group during nick change */
+#define NS_TEMPORARY	0xFF00      /* All temporary status flags */
+/* These two are not used anymore */
+#define NS_OLD_ENCRYPTEDPW	0x0001  /* Nickname password is encrypted */
+
+/* Nickname setting flags: */
+#define NI_KILLPROTECT		0x00000001  /* Kill others who take this nick */
+#define NI_SECURE			0x00000002  /* Don't recognize unless IDENTIFY'd */
+#define NI_MSG              0x00000004	/* Use PRIVMSGs instead of NOTICEs */
+#define NI_MEMO_HARDMAX		0x00000008  /* Don't allow user to change memo limit */
+#define NI_MEMO_SIGNON		0x00000010  /* Notify of memos at signon and un-away */
+#define NI_MEMO_RECEIVE		0x00000020  /* Notify of new memos when sent */
+#define NI_PRIVATE			0x00000040  /* Don't show in LIST to non-servadmins */
+#define NI_HIDE_EMAIL		0x00000080  /* Don't show E-mail in INFO */
+#define NI_HIDE_MASK		0x00000100  /* Don't show last seen address in INFO */
+#define NI_HIDE_QUIT		0x00000200  /* Don't show last quit message in INFO */
+#define NI_KILL_QUICK		0x00000400  /* Kill in 20 seconds instead of 60 */
+#define NI_KILL_IMMED		0x00000800  /* Kill immediately instead of in 60 sec */
+#define NI_SERVICES_OPER 	0x00001000	/* User is a Services operator */
+#define NI_SERVICES_ADMIN	0x00002000	/* User is a Services admin */
+#define NI_ENCRYPTEDPW		0x00004000	/* Nickname password is encrypted */
+#define NI_SERVICES_ROOT    0x00008000  /* User is a Services root */
+
+/* Languages.  Never insert anything in the middle of this list, or
+ * everybody will start getting the wrong language!  If you want to change
+ * the order the languages are displayed in for NickServ HELP SET LANGUAGE,
+ * do it in language.c.
+ */
+#define LANG_EN_US              0	/* United States English */
+#define LANG_JA_JIS             1	/* Japanese (JIS encoding) */
+#define LANG_JA_EUC             2	/* Japanese (EUC encoding) */
+#define LANG_JA_SJIS            3	/* Japanese (SJIS encoding) */
+#define LANG_ES                 4	/* Spanish */
+#define LANG_PT                 5	/* Portugese */
+#define LANG_FR                 6	/* French */
+#define LANG_TR                 7	/* Turkish */
+#define LANG_IT                 8	/* Italian */
+#define LANG_DE                 9   /* German */
+#define LANG_CAT               10   /* Catalan */
+#define LANG_GR                11   /* Greek */
+#define LANG_NL                12   /* Dutch */
+#define LANG_RU                13   /* Russian */
+
+#define NUM_LANGS              14	/* Number of languages */
+#define USED_LANGS             11	/* Number of languages provided */
+
+#define DEF_LANGUAGE	LANG_EN_US
+
+/*************************************************************************/
+
+/* Bot info structures. Note that since there won't be many bots,
+ * they're not in a hash list.
+ *	--lara
+ */
+
+typedef struct botinfo_ BotInfo;
+
+struct botinfo_ {
+
+ 	BotInfo *next, *prev;
+
+ 	char *nick;    			/* Nickname of the bot */
+ 	char *user;    			/* Its user name */
+ 	char *host;    			/* Its hostname */
+ 	char *real;     		/* Its real name */
+
+ 	int16 flags;			/* Bot flags -- see BI_* below */
+
+ 	time_t created; 		/* Birth date ;) */
+	int16 chancount;		/* Number of channels that use the bot. */
+
+	/* Dynamic data */
+ 	time_t lastmsg;			/* Last time we said something */
+};
+
+#define BI_PRIVATE		0x0001
+
+/* Channel info structures.  Stored similarly to the nicks, except that
+ * the second character of the channel name, not the first, is used to
+ * determine the list.  (Hashing based on the first character of the name
+ * wouldn't get very far. ;) ) */
+
+/* Access levels for users. */
+typedef struct {
+    int16 in_use;	/* 1 if this entry is in use, else 0 */
+    int16 level;
+    NickCore *nc;	/* Guaranteed to be non-NULL if in use, NULL if not */
+    time_t last_seen;
+} ChanAccess;
+
+/* Note that these two levels also serve as exclusive boundaries for valid
+ * access levels.  ACCESS_FOUNDER may be assumed to be strictly greater
+ * than any valid access level, and ACCESS_INVALID may be assumed to be
+ * strictly less than any valid access level.
+ */
+#define ACCESS_FOUNDER	10000	/* Numeric level indicating founder access */
+#define ACCESS_INVALID	-10000	/* Used in levels[] for disabled settings */
+
+/* Levels for xOP */
+
+#define ACCESS_VOP		3
+#ifdef HAS_HALFOP
+# define ACCESS_HOP      4
+#endif
+#define ACCESS_AOP		5
+#define ACCESS_SOP		10
+
+/* AutoKick data. */
+typedef struct {
+    int16 in_use;   /* Always 0 if not in use */
+    int16 is_nick;	/* 1 if a regged nickname, 0 if a nick!user@host mask */
+
+	int16 flags;
+
+    union {
+		char *mask;		/* Guaranteed to be non-NULL if in use, NULL if not */
+		NickCore *nc;	/* Same */
+    } u;
+    char *reason;
+
+    char *creator;
+    time_t addtime;
+} AutoKick;
+
+#define AK_USED		0x0001
+#define AK_ISNICK	0x0002
+#define AK_STUCK    0x0004
+
+/* Structure used to contain bad words. */
+
+typedef struct badword_ BadWord;
+
+struct badword_ {
+	int16 in_use;
+
+	char *word;
+	int16 type;		/* BW_* below */
+};
+
+#define BW_ANY 		0
+#define BW_SINGLE 	1
+#define BW_START 	2
+#define BW_END 		3
+
+typedef struct chaninfo_ ChannelInfo;
+struct chaninfo_ {
+    ChannelInfo *next, *prev;
+    char name[CHANMAX];
+    NickCore *founder;
+    NickCore *successor;		/* Who gets the channel if the founder
+					 			 * nick is dropped or expires */
+    char founderpass[PASSMAX];
+    char *desc;
+    char *url;
+    char *email;
+
+    time_t time_registered;
+    time_t last_used;
+    char *last_topic;			/* Last topic on the channel */
+    char last_topic_setter[NICKMAX];	/* Who set the last topic */
+    time_t last_topic_time;		/* When the last topic was set */
+
+    uint32 flags;				/* See below */
+    char *forbidby;
+    char *forbidreason;
+
+    int16 bantype;
+
+    int16 *levels;				/* Access levels for commands */
+
+    int16 accesscount;
+    ChanAccess *access;			/* List of authorized users */
+    int16 akickcount;
+    AutoKick *akick;			/* List of users to kickban */
+
+    uint32 mlock_on, mlock_off;	/* See channel modes below */
+    uint32 mlock_limit;			/* 0 if no limit */
+    char *mlock_key;			/* NULL if no key */
+#ifdef HAS_FMODE
+    char *mlock_flood;			/* NULL if no +f */
+#endif
+#ifdef HAS_LMODE
+    char *mlock_redirect;		/* NULL if no +L */
+#endif
+
+    char *entry_message;		/* Notice sent on entering channel */
+
+    MemoInfo memos;
+
+    struct channel_ *c;			/* Pointer to channel record (if   *
+					 			 *    channel is currently in use) */
+
+    /* For BotServ */
+
+    BotInfo *bi;					/* Bot used on this channel */
+    uint32 botflags;				/* BS_* below */
+    int16 *ttb;						/* Times to ban for each kicker */
+
+    int16 bwcount;
+    BadWord *badwords;				/* For BADWORDS kicker */
+    int16 capsmin, capspercent;		/* For CAPS kicker */
+    int16 floodlines, floodsecs;	/* For FLOOD kicker */
+    int16 repeattimes;				/* For REPEAT kicker */
+};
+
+/* Retain topic even after last person leaves channel */
+#define CI_KEEPTOPIC	0x00000001
+/* Don't allow non-authorized users to be opped */
+#define CI_SECUREOPS	0x00000002
+/* Hide channel from ChanServ LIST command */
+#define CI_PRIVATE	0x00000004
+/* Topic can only be changed by SET TOPIC */
+#define CI_TOPICLOCK	0x00000008
+/* Those not allowed ops are kickbanned */
+#define CI_RESTRICTED	0x00000010
+/* Don't allow ChanServ and BotServ commands to do bad things to bigger levels */
+#define CI_PEACE  0x00000020
+/* Don't allow any privileges unless a user is IDENTIFY'd with NickServ */
+#define CI_SECURE	0x00000040
+/* Don't allow the channel to be registered or used */
+#define CI_VERBOTEN	0x00000080
+/* Channel password is encrypted */
+#define CI_ENCRYPTEDPW	0x00000100
+/* Channel does not expire */
+#define CI_NO_EXPIRE	0x00000200
+/* Channel memo limit may not be changed */
+#define CI_MEMO_HARDMAX	0x00000400
+/* Send notice to channel on use of OP/DEOP */
+#define CI_OPNOTICE	0x00000800
+/* Stricter control of channel founder status */
+#define CI_SECUREFOUNDER 0x00001000
+/* Always sign kicks */
+#define CI_SIGNKICK 0x00002000
+/* Sign kicks if level is < than the one defined by the SIGNKICK level */
+#define CI_SIGNKICK_LEVEL 0x00004000
+/* Use the xOP lists */
+#define CI_XOP 0x00008000
+/* Channel is suspended */
+#define CI_SUSPENDED 0x00010000
+
+/* TEMPORARY - ChanServ is on the channel. */
+#define CI_INHABIT 0x80000000
+
+/* Indices for cmd_access[]: */
+#define CA_INVITE			0
+#define CA_AKICK			1
+#define CA_SET				2	/* but not FOUNDER or PASSWORD */
+#define CA_UNBAN			3
+#define CA_AUTOOP			4
+#define CA_AUTODEOP			5	/* Maximum, not minimum */
+#define CA_AUTOVOICE		6
+#define CA_OPDEOP			7	/* ChanServ commands OP and DEOP */
+#define CA_ACCESS_LIST		8
+#define CA_CLEAR			9
+#define CA_NOJOIN			10	/* Maximum */
+#define CA_ACCESS_CHANGE 	11
+#define CA_MEMO				12
+#define CA_ASSIGN       	13  /* BotServ ASSIGN command */
+#define CA_BADWORDS     	14  /* BotServ BADWORDS command */
+#define CA_NOKICK       	15  /* Not kicked by the bot */
+#define CA_FANTASIA   		16
+#define CA_SAY				17
+#define CA_GREET            18
+#define CA_VOICEME			19
+#define CA_VOICE			20
+#define CA_GETKEY           21
+#define CA_AUTOHALFOP		22
+#define CA_AUTOPROTECT		23
+#define CA_OPDEOPME         24
+#define CA_HALFOPME         25
+#define CA_HALFOP           26
+#define CA_PROTECTME        27
+#define CA_PROTECT          28
+#define CA_KICKME           29
+#define CA_KICK             30
+#define CA_SIGNKICK			31
+/* #define CA_AUTOADMIN        32
+#define CA_ADMINME          33
+#define CA_ADMIN            34 */
+#define CA_BANME            32
+#define CA_BAN              33
+#define CA_TOPIC            34
+#define CA_INFO             35
+
+#define CA_SIZE		36
+
+/* BotServ SET flags */
+#define BS_DONTKICKOPS      0x00000001
+#define BS_DONTKICKVOICES   0x00000002
+#define BS_FANTASY          0x00000004
+#define BS_SYMBIOSIS        0x00000008
+#define BS_GREET            0x00000010
+#define BS_NOBOT            0x00000020
+
+/* BotServ Kickers flags */
+#define BS_KICK_BOLDS 		0x80000000
+#define BS_KICK_COLORS 		0x40000000
+#define BS_KICK_REVERSES	0x20000000
+#define BS_KICK_UNDERLINES	0x10000000
+#define BS_KICK_BADWORDS	0x08000000
+#define BS_KICK_CAPS		0x04000000
+#define BS_KICK_FLOOD		0x02000000
+#define BS_KICK_REPEAT		0x01000000
+
+/* Indices for TTB (Times To Ban) */
+#define TTB_BOLDS 		0
+#define TTB_COLORS 		1
+#define TTB_REVERSES	2
+#define TTB_UNDERLINES  3
+#define TTB_BADWORDS	4
+#define TTB_CAPS		5
+#define TTB_FLOOD		6
+#define TTB_REPEAT		7
+
+#define TTB_SIZE 		8
+
+/*************************************************************************/
+
+/* ChanServ mode utilities commands */
+
+typedef struct csmodeutil_ CSModeUtil;
+
+struct csmodeutil_ {
+	char *name;				/* Name of the ChanServ command */
+	char *bsname;			/* Name of the BotServ fantasy command */
+
+	char *mode;				/* Mode (ie. +o) */
+	int32 notice;			/* Notice flag (for the damn OPNOTICE) */
+
+	int level;				/* Level required to use the command */
+	int levelself;			/* Level required to use the command for himself */
+};
+
+#define MUT_DEOP   		0
+#define MUT_OP			1
+#define MUT_DEVOICE		2
+#define MUT_VOICE		3
+#ifdef HAS_HALFOP
+#define MUT_DEHALFOP	4
+#define MUT_HALFOP		5
+#endif
+#ifdef IRC_UNREAL
+#define MUT_DEPROTECT   6
+#define MUT_PROTECT     7
+#endif
+#ifdef IRC_ULTIMATE3
+#define MUT_DEPROTECT   6
+#define MUT_PROTECT     7
+#endif
+#ifdef IRC_VIAGRA
+#define MUT_DEPROTECT   6
+#define MUT_PROTECT     7
+#endif
+/*************************************************************************/
+
+/* Online user and channel data. */
+
+struct user_ {
+    User *next, *prev;
+
+    char nick[NICKMAX];
+
+    char *username;
+    char *host;             /* User's real hostname */
+#ifdef HAS_VHOST
+    char *vhost;            /* User's virtual hostname */
+#endif
+#ifdef HAS_VIDENT
+    char *vident;           /* User's virtual ident */
+#endif
+    char *realname;
+    char *server;			/* Name of server user is on */
+
+    time_t timestamp;		/* Timestamp of the nick */
+    time_t my_signon;		/* When did _we_ see the user? */
+    uint32 svid;			/* Services ID */
+    uint32 mode;			/* See below */
+
+    NickAlias *na;
+
+    int isSuperAdmin;		/* is SuperAdmin on or off? */
+
+    struct u_chanlist {
+		struct u_chanlist *next, *prev;
+		Channel *chan;
+		int16 status;		/* Associated flags; see CSTATUS_* below. */
+    } *chans;				/* Channels user has joined */
+
+    struct u_chaninfolist {
+		struct u_chaninfolist *next, *prev;
+		ChannelInfo *chan;
+    } *founder_chans;			/* Channels user has identified for */
+
+    short invalid_pw_count;		/* # of invalid password attempts */
+    time_t invalid_pw_time;		/* Time of last invalid password */
+
+    time_t lastmemosend;		/* Last time MS SEND command used */
+    time_t lastnickreg;			/* Last time NS REGISTER cmd used */
+    time_t lastmail;			/* Last time this user sent a mail */
+};
+
+#define UMODE_a 0x00000001
+#define UMODE_h 0x00000002
+#define UMODE_i 0x00000004
+#define UMODE_o 0x00000008
+#define UMODE_r 0x00000010
+#define UMODE_w 0x00000020
+#define UMODE_A 0x00000040
+
+#ifdef IRC_ULTIMATE
+#define UMODE_p 0x04000000
+#define UMODE_R 0x08000000
+#define UMODE_P 0x20000000
+#endif
+
+#ifdef IRC_ULTIMATE3
+#define UMODE_p 0x04000000
+#define UMODE_Z 0x08000000
+#define UMODE_P 0x20000000
+#endif
+
+#ifdef IRC_DREAMFORGE
+# define UMODE_g 0x80000000
+#endif
+
+#ifdef IRC_BAHAMUT
+# define UMODE_R 0x80000000
+#endif
+
+#ifdef IRC_VIAGRA
+#define UMODE_p 0x04000000
+#endif
+
+#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_VIAGRA)
+# define UMODE_x 0x40000000
+#endif
+
+/* Returns *current* user hostname */
+#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_VIAGRA)
+# define GetHost(x)      ((x)->mode & UMODE_x ? (x)->vhost : (x)->host)
+#elif defined(IRC_PTLINK)
+# define GetHost(x)      ((x)->mode & UMODE_o ? (x)->vhost ? (x)->vhost : (x)->host : (x)->host)
+#else
+# define GetHost(x)      ((x)->host)
+#endif
+
+/* Returns *current* user ident */
+#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_VIAGRA)
+# define GetIdent(x)      ((x)->mode & UMODE_x ? (x)->vident ? (x)->vident : (x)->username : (x)->username)
+#else
+# define GetIdent(x)      ((x)->username)
+#endif
+
+/* This will introduce a pseudo client with the given nick, username, hostname,
+   realname and modes. It will also make a Q line for the nick on demand.
+   	--lara */
+#if defined(IRC_HYBRID)
+# define NEWNICK(nick,user,host,real,modes,qline) \
+    do { \
+	kill_user(NULL, (nick), "Nick used by Services"); \
+	send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s :%s", (nick), time(NULL), (modes), \
+		(user), (host), ServerName, (real)); \
+	} while (0)
+#elif defined(IRC_ULTIMATE3)
+# define NEWNICK(nick,user,host,real,modes,qline) \
+    do { \
+	send_cmd(NULL, "CLIENT %s 1 %ld %s + %s %s * %s 0 0 :%s", (nick), time(NULL), (modes), \
+		(user), (host), ServerName, (real)); \
+	if ((qline)) send_cmd(NULL, "SQLINE %s :Reserved for services", (nick)); \
+    } while (0)
+#elif defined(IRC_BAHAMUT) && !defined(IRC_ULTIMATE3)
+# define NEWNICK(nick,user,host,real,modes,qline) \
+    do { \
+	send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", (nick), time(NULL), (modes), \
+		(user), (host), ServerName, (real)); \
+	if ((qline)) send_cmd(NULL, "SQLINE %s :Reserved for services", (nick)); \
+    } while (0)
+#elif defined(IRC_UNREAL)
+# define NEWNICK(nick,user,host,real,modes,qline) \
+    do { \
+	send_cmd(NULL, "NICK %s 1 %ld %s %s %s 0 %s * :%s", (nick), time(NULL), \
+		(user), (host), ServerName, (modes), (real)); \
+	if ((qline)) send_cmd(NULL, "SQLINE %s :Reserved for services", (nick)); \
+    } while (0)
+#elif defined(IRC_DREAMFORGE)
+# define NEWNICK(nick,user,host,real,modes,qline) \
+    do { \
+	send_cmd(NULL, "NICK %s 1 %ld %s %s %s 0 :%s", (nick), time(NULL), \
+		(user), (host), ServerName, (real)); \
+	if (strcmp(modes, "+")) send_cmd((nick), "MODE %s %s", (nick), (modes)); \
+	if ((qline)) send_cmd(NULL, "SQLINE %s :Reserved for services", (nick)); \
+    } while (0)
+#elif defined(IRC_PTLINK)
+# define NEWNICK(nick,user,host,real,modes,qline) \
+    do { \
+        send_cmd(NULL, "NICK %s 1 %lu %s %s %s %s %s :%s", (nick), time(NULL), \
+                (modes), (user), (host), (host), ServerName, (real)); \
+       if ((qline)) send_cmd(NULL, "SQLINE %s :Reserved for services", (nick)); \
+    } while (0)
+#endif
+
+typedef struct cbmode_ CBMode;
+typedef struct cbmodeinfo_ CBModeInfo;
+typedef struct cmmode_ CMMode;
+typedef struct csmode_ CSMode;
+typedef struct cumode_ CUMode;
+
+struct cbmode_ {
+	uint32 flag;			/* Long value that represents the mode */
+	uint16 flags;			/* Flags applying to this mode (CBM_* below) */
+
+	/* Function to associate a value with the mode */
+	void (*setvalue)	(Channel *chan, char *value);
+	void (*cssetvalue)	(ChannelInfo *ci, char *value);
+};
+
+#define CBM_MINUS_NO_ARG 	0x0001		/* No argument for unset */
+#define CBM_NO_MLOCK		0x0002		/* Can't be MLOCKed */
+#define CBM_NO_USER_MLOCK   0x0004      /* Can't be MLOCKed by non-opers */
+
+struct cbmodeinfo_ {
+	char mode;				/* The mode */
+	uint32 flag;			/* Long value that represents the mode */
+	uint16 flags;			/* CBM_* above */
+
+	/* Function to retrieve the value associated to the mode (optional) */
+	char * (*getvalue) 		(Channel *chan);
+	char * (*csgetvalue) 	(ChannelInfo *ci);
+};
+
+struct cmmode_ {
+	void (*addmask) (Channel *chan, char *mask);
+	void (*delmask) (Channel *chan, char *mask);
+};
+
+struct cumode_ {
+	int16 status;			/* CUS_* below */
+	int16 flags;			/* CUF_* below */
+
+	int (*is_valid) (User *user, Channel *chan, int servermode);
+};
+
+/* User flags on channel */
+#define CUS_OP			0x0001
+#define CUS_VOICE		0x0002
+
+#ifdef HAS_HALFOP
+#define CUS_HALFOP		0x0004		/* Halfop (+h) */
+#endif
+
+/* Used by Unreal */
+#ifdef IRC_UNREAL
+#define CUS_OWNER		0x0008		/* Owner/Founder (+q) */
+#define CUS_PROTECT		0x0010		/* Protected users (+a) */
+#endif
+
+/* Used by Viagra */
+#ifdef IRC_VIAGRA
+#define CUS_OWNER		0x0008		/* Owner/Founder (+q) */
+#define CUS_PROTECT		0x0010		/* Protected users (+a) */
+#endif
+
+#ifdef IRC_ULTIMATE3
+#define CUS_PROTECT		0x0010		/* Protected users (+a) */
+#endif
+
+/* Used by PTlink */
+#ifdef IRC_PTLINK
+#define CUS_PROTECT            0x0016          /* Protected users (+a) */
+#endif
+
+/* Channel user mode flags */
+
+#define CUF_PROTECT_BOTSERV 	0x0001
+
+/* Useful value */
+
+#if defined(IRC_ULTIMATE)
+# define CHAN_MAX_SYMBOLS   3
+#elif defined(IRC_ULTIMATE3)
+# define CHAN_MAX_SYMBOLS  5
+#elif defined(IRC_UNREAL)
+# define CHAN_MAX_SYMBOLS	5
+#else
+# define CHAN_MAX_SYMBOLS   2
+#endif
+
+/* Binary modes that need to be cleared */
+
+#if defined(IRC_BAHAMUT)
+#define MODESTOREMOVE "-ciklmnpstOR"
+#elif defined(IRC_ULTIMATE)
+#define MODESTOREMOVE "-kiflmnpstxAIKLORS"
+#elif defined(IRC_ULTIMATE3)
+#define MODESTOREMOVE "-iklmnpstRKAO"
+#elif defined(IRC_UNREAL)
+#define MODESTOREMOVE "-ckiflmnpstuzACGHKLNOQRSV"
+#elif defined(IRC_PTLINK)
+#define MODESTOREMOVE "-cdfiklmnpqstRS"
+#else
+#define MODESTOREMOVE "-iklmnpstR"
+#endif
+
+typedef struct bandata_ BanData;
+typedef struct userdata_ UserData;
+
+/* This structure stocks ban data since it must not be removed when
+ * user is kicked.
+ */
+
+struct bandata_ {
+    BanData *next, *prev;
+
+    char *mask;				/* Since a nick is unsure and a User structure
+    					   	   is unsafe */
+    time_t last_use;		/* Since time is the only way to check
+    					   	   whether it's still useful */
+    int16 ttb[TTB_SIZE];
+};
+
+/* This structure stocks information on every user that will be used by
+ * BotServ. */
+
+struct userdata_ {
+    /* Data validity */
+    time_t last_use;
+
+    /* for flood kicker */
+    int16 lines;
+    time_t last_start;
+
+    /* for repeat kicker */
+    char *lastline;
+    int16 times;
+};
+
+struct channel_ {
+    Channel *next, *prev;
+    char name[CHANMAX];
+    ChannelInfo *ci;			/* Corresponding ChannelInfo */
+    time_t creation_time;		/* When channel was created */
+
+    char *topic;
+    char topic_setter[NICKMAX];		/* Who set the topic */
+    time_t topic_time;			/* When topic was set */
+
+    uint32 mode;				/* Binary modes only */
+    uint32 limit;			/* 0 if none */
+    char *key;				/* NULL if none */
+#ifdef HAS_LMODE
+	char *redirect;			/* +L; NULL if none */
+#endif
+#ifdef HAS_FMODE
+	char *flood;			/* +f; NULL if none */
+#endif
+
+    int32 bancount, bansize;
+    char **bans;
+
+    int32 exceptcount, exceptsize;
+    char **excepts;
+
+    struct c_userlist {
+		struct c_userlist *next, *prev;
+		User *user;
+		UserData *ud;
+    } *users;
+    int16 usercount;
+
+    BanData *bd;
+
+    time_t server_modetime;		/* Time of last server MODE */
+    time_t chanserv_modetime;	/* Time of last check_modes() */
+    int16 server_modecount;		/* Number of server MODEs this second */
+    int16 chanserv_modecount;	/* Number of check_mode()'s this sec */
+    int16 bouncy_modes;			/* Did we fail to set modes here? */
+};
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040		/* These two used only by ChanServ */
+#define CMODE_l 0x00000080
+
+/* The two modes below are for IRC_DREAMFORGE servers only. */
+#ifndef IRC_HYBRID
+#define CMODE_R 0x00000100		/* Only identified users can join */
+#define CMODE_r 0x00000200		/* Set for all registered channels */
+#endif
+
+/* This mode is for IRC_BAHAMUT servers only. */
+#ifdef IRC_BAHAMUT
+#define CMODE_c 0x00000400		/* Colors can't be used */
+#define CMODE_M 0x00000800      /* Non-regged nicks can't send messages */
+#define CMODE_O 0x00008000		/* Only opers can join */
+#endif
+
+/* This mode is for IRC_HYBRID servers only. */
+#ifdef IRC_HYBRID
+#define CMODE_a 0x00000400
+#endif
+
+/* These modes are for IRC_ULTIMATE servers only. */
+#ifdef IRC_ULTIMATE
+#define CMODE_f 0x00000400
+#define CMODE_x 0x00000800
+#define CMODE_A 0x00001000
+#define CMODE_I 0x00002000
+#define CMODE_K 0x00004000
+#define CMODE_L 0x00008000
+#define CMODE_O 0x00010000
+#define CMODE_S 0x00020000
+#endif
+
+/* These modes are for IRC_UNREAL servers only. */
+#ifdef IRC_UNREAL
+#define CMODE_c 0x00000400
+#define CMODE_A 0x00000800
+#define CMODE_H 0x00001000
+#define CMODE_K 0x00002000
+#define CMODE_L 0x00004000
+#define CMODE_O 0x00008000
+#define CMODE_Q 0x00010000
+#define CMODE_S 0x00020000
+#define CMODE_V 0x00040000
+#define CMODE_f 0x00080000
+#define CMODE_G 0x00100000
+#define CMODE_C 0x00200000
+#define CMODE_u 0x00400000
+#define CMODE_z 0x00800000
+#define CMODE_N 0x01000000
+#endif
+
+/* These modes are for IRC_ULTIMATE3 servers only */
+#ifdef IRC_ULTIMATE3
+#define CMODE_A 0x00000800
+#define CMODE_N 0x00001000
+#define CMODE_S 0x00002000
+#define CMODE_K 0x00004000
+#endif
+
+/* These modes are for IRC_PTLINK servers only. */
+#ifdef IRC_PTLINK
+#define CMODE_A 0x00000400
+#define CMODE_B 0x00000800
+#define CMODE_c 0x00001000
+#define CMODE_d 0x00002000
+#define CMODE_f 0x00004000
+#define CMODE_K 0x00008000
+#define CMODE_O 0x00010000
+#define CMODE_q 0x00020000
+#define CMODE_S 0x00040000
+#define CMODE_N 0x00080000
+#endif
+
+
+/*************************************************************************/
+
+/* Constants for news types. */
+
+#define NEWS_LOGON		0
+#define NEWS_OPER		1
+#define NEWS_RANDOM 	2
+
+/*************************************************************************/
+
+/* Ignorance list data. */
+
+typedef struct ignore_data {
+    struct ignore_data *next;
+    char who[NICKMAX];
+    time_t time;	/* When do we stop ignoring them? */
+} IgnoreData;
+
+/*************************************************************************/
+
+/* Mail data */
+
+typedef struct mailinfo_ MailInfo;
+
+struct mailinfo_ {
+	FILE *pipe;
+	User *sender;
+	NickCore *recipient;
+	NickRequest *recip;
+};
+
+/*************************************************************************/
+
+typedef struct akill_ Akill;
+
+struct akill_ {
+	char *user;			/* User part of the AKILL */
+	char *host;			/* Host part of the AKILL */
+
+	char *by;			/* Who set the akill */
+	char *reason;		/* Why they got akilled */
+
+	time_t seton;		/* When it was set */
+	time_t expires;		/* When it expires */
+};
+
+/*************************************************************************/
+
+/* Structure for OperServ SGLINE and SZLINE commands */
+
+typedef struct sxline_ SXLine;
+
+struct sxline_ {
+	char *mask;
+	char *by;
+	char *reason;
+	time_t seton;
+	time_t expires;
+};
+
+/*************************************************************************/
+
+/* Host serv structures */
+
+typedef struct hostcore_ HostCore;
+
+struct hostcore_ {
+    HostCore *next;
+    char *nick;				/* Owner of the vHost */
+    char *vIdent;			/* vIdent for the user */
+    char *vHost;			/* Vhost for this user */
+    char *creator;			/* Oper Nick of the oper who set the vhost */
+    time_t time;			/* Date/Time vHost was set */
+};
+
+/*************************************************************************/
+
+typedef struct newsitem_ NewsItem;
+
+struct newsitem_ {
+    int16 type;
+    int32 num;                  /* Numbering is separate for login and oper news */
+    char *text;
+    char who[NICKMAX];
+    time_t time;
+};
+
+/*************************************************************************/
+
+typedef struct exception_ Exception;
+struct exception_ {
+    char *mask;                 /* Hosts to which this exception applies */
+    int limit;                  /* Session limit for exception */
+    char who[NICKMAX];          /* Nick of person who added the exception */
+    char *reason;               /* Reason for exception's addition */
+    time_t time;                /* When this exception was added */
+    time_t expires;             /* Time when it expires. 0 == no expiry */
+    int num;                    /* Position in exception list; used to track
+                                 * positions when deleting entries. It is
+                                 * symbolic and used internally. It is
+                                 * calculated at load time and never saved. */
+};
+
+/*************************************************************************/
+
+/* Proxy stuff */
+
+typedef struct hostcache_ HostCache;
+
+struct hostcache_ {
+	HostCache *prev, *next;
+
+	char *host;							/* The hostname */
+	uint32 ip;							/* The IP address */
+
+	int16 status;						/* HC_* below */
+	time_t used;						/* When was this entry last used? */
+};
+
+/* We assume that values < 0 are in-progress values, and values > 0 are
+ * proxy value. 0 is the normal value.
+ */
+
+#define HC_QUEUED		-2				/* Waiting to be scanned */
+#define HC_PROGRESS		-1				/* Currently being scanned */
+#define HC_NORMAL		 0				/* No proxy found on this host */
+#define HC_WINGATE		 1				/* Wingate found */
+#define HC_SOCKS4		 2				/* Socks4 found */
+#define HC_SOCKS5		 3				/* Socks5 found */
+#define HC_HTTP			 4				/* HTTP proxy found */
+
+/**
+ * DEFCON Defines
+ **/
+#define DEFCON_NO_NEW_CHANNELS 		1	/* No New Channel Registrations */
+#define DEFCON_NO_NEW_NICKS 		2	/* No New Nick Registrations */
+#define DEFCON_NO_MLOCK_CHANGE		4	/* No MLOCK changes */
+#define DEFCON_FORCE_CHAN_MODES		8	/* Force Chan Mode */
+#define DEFCON_REDUCE_SESSION		16	/* Reduce Session Limit */
+#define DEFCON_NO_NEW_CLIENTS		32	/* Kill any NEW clients */
+#define DEFCON_OPER_ONLY		64	/* Restrict services to oper's only */
+#define DEFCON_SILENT_OPER_ONLY		128	/* Silently ignore non-opers */
+#define DEFCON_AKILL_NEW_CLIENTS	256	/* AKILL any new clients */
+#define DEFCON_NO_NEW_MEMOS		512	/* No New Memos Sent */
+/*************************************************************************/
+
+#include "extern.h"
+
+/*************************************************************************/
+
+#endif	/* SERVICES_H */
diff -ruN orig/anope-1.6.2/users.c anope-1.6.2/users.c
--- orig/anope-1.6.2/users.c	2004-04-19 02:36:02.000000000 +0000
+++ anope-1.6.2/users.c	2004-07-20 01:20:34.000000000 +0000
@@ -160,7 +160,7 @@
 
 /*************************************************************************/
 
-#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_VIAGRA) || defined(IRC_PTLINK)
+#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_VIAGRA) || defined(IRC_PTLINK) || defined(IRC_HYBRID)
 
 /* Change the (virtual) hostname of a user. */
 
diff -ruN orig/anope-1.6.2/users.c.orig anope-1.6.2/users.c.orig
--- orig/anope-1.6.2/users.c.orig	1970-01-01 00:00:00.000000000 +0000
+++ anope-1.6.2/users.c.orig	2004-04-19 02:36:02.000000000 +0000
@@ -0,0 +1,1136 @@
+/* Routines to maintain a list of online users.
+ *
+ * (C) 2003 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church. 
+ * 
+ * $Id: users.c 5 2004-03-29 01:29:50Z dane $
+ *
+ */
+
+#include "services.h"
+
+#define HASH(nick)	(((nick)[0]&31)<<5 | ((nick)[1]&31))
+User *userlist[1024];
+
+int32 usercnt = 0, opcnt = 0, maxusercnt = 0;
+time_t maxusertime;
+
+static unsigned long umodes[128] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, UMODE_A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#if defined(IRC_ULTIMATE) || defined(IRC_ULTIMATE3)
+    UMODE_P,
+#else
+    0,
+#endif
+    0,
+#if defined(IRC_BAHAMUT) || defined(IRC_ULTIMATE)
+    UMODE_R,
+#else
+    0,
+#endif
+    0, 0, 0, 0, 0, 0, 0,
+#ifdef IRC_ULTIMATE3
+    UMODE_Z,
+#else
+    0,
+#endif
+    0, 0, 0, 0, 0,
+    0, UMODE_a, 0, 0, 0, 0, 0,
+#ifdef IRC_DREAMFORGE
+    UMODE_g,
+#else
+    0,
+#endif
+    UMODE_h, UMODE_i, 0, 0, 0, 0, 0, UMODE_o,
+#if defined(IRC_ULTIMATE) || defined(IRC_ULTIMATE3)
+    UMODE_p,
+#else
+    0,
+#endif
+    0, UMODE_r, 0, 0, 0, 0, UMODE_w,
+#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_VIAGRA)
+    UMODE_x,
+#else
+    0,
+#endif
+    0, 0, 0, 0, 0, 0, 0
+};
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Allocate a new User structure, fill in basic values, link it to the
+ * overall list, and return it.  Always successful.
+ */
+
+static User *new_user(const char *nick)
+{
+    User *user, **list;
+
+    user = scalloc(sizeof(User), 1);
+    if (!nick)
+        nick = "";
+    strscpy(user->nick, nick, NICKMAX);
+    list = &userlist[HASH(user->nick)];
+    user->next = *list;
+    if (*list)
+        (*list)->prev = user;
+    *list = user;
+    user->na = findnick(nick);
+    if (user->na)
+        user->na->u = user;
+    usercnt++;
+    if (usercnt > maxusercnt) {
+        maxusercnt = usercnt;
+        maxusertime = time(NULL);
+        if (LogMaxUsers)
+            alog("user: New maximum user count: %d", maxusercnt);
+    }
+    user->isSuperAdmin = 0;     /* always set SuperAdmin to 0 for new users */
+    return user;
+}
+
+/*************************************************************************/
+
+/* Change the nickname of a user, and move pointers as necessary. */
+
+static void change_user_nick(User * user, const char *nick)
+{
+    User **list;
+    int is_same = (!stricmp(user->nick, nick) ? 1 : 0);
+
+    if (user->prev)
+        user->prev->next = user->next;
+    else
+        userlist[HASH(user->nick)] = user->next;
+    if (user->next)
+        user->next->prev = user->prev;
+    user->nick[1] = 0;          /* paranoia for zero-length nicks */
+    strscpy(user->nick, nick, NICKMAX);
+    list = &userlist[HASH(user->nick)];
+    user->next = *list;
+    user->prev = NULL;
+    if (*list)
+        (*list)->prev = user;
+    *list = user;
+
+    /* Only if old and new nick aren't the same; no need to waste time */
+    if (!is_same) {
+        if (user->na)
+            user->na->u = NULL;
+        user->na = findnick(nick);
+        if (user->na)
+            user->na->u = user;
+    }
+}
+
+/*************************************************************************/
+
+#ifdef HAS_VHOST
+
+static void update_host(User * user)
+{
+    if (user->na && (nick_identified(user)
+                     || (!(user->na->nc->flags & NI_SECURE)
+                         && nick_recognized(user)))) {
+        if (user->na->last_usermask)
+            free(user->na->last_usermask);
+
+        user->na->last_usermask =
+            smalloc(strlen(GetIdent(user)) + strlen(GetHost(user)) + 2);
+        sprintf(user->na->last_usermask, "%s@%s", GetIdent(user),
+                GetHost(user));
+    }
+
+    if (debug)
+        alog("debug: %s changes its host to %s", user->nick,
+             GetHost(user));
+}
+
+#endif
+
+/*************************************************************************/
+
+#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_VIAGRA) || defined(IRC_PTLINK)
+
+/* Change the (virtual) hostname of a user. */
+
+void change_user_host(User * user, const char *host)
+{
+    if (user->vhost)
+        free(user->vhost);
+    user->vhost = sstrdup(host);
+
+    if (debug)
+        alog("debug: %s changes its vhost to %s", user->nick, host);
+
+
+
+    update_host(user);
+}
+
+#endif
+/*************************************************************************/
+
+#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_VIAGRA) || defined(IRC_PTLINK)
+/* Change the realname of a user. */
+
+void change_user_realname(User * user, const char *realname)
+{
+    if (user->realname)
+        free(user->realname);
+    user->realname = sstrdup(realname);
+
+    if (user->na && (nick_identified(user)
+                     || (!(user->na->nc->flags & NI_SECURE)
+                         && nick_recognized(user)))) {
+        if (user->na->last_realname)
+            free(user->na->last_realname);
+        user->na->last_realname = sstrdup(realname);
+    }
+
+    if (debug)
+        alog("debug: %s changes its realname to %s", user->nick, realname);
+}
+
+
+/*************************************************************************/
+
+/* Change the username of a user. */
+
+void change_user_username(User * user, const char *username)
+{
+    if (user->username)
+        free(user->username);
+    user->username = sstrdup(username);
+    if (user->na && (nick_identified(user)
+                     || (!(user->na->nc->flags & NI_SECURE)
+                         && nick_recognized(user)))) {
+        if (user->na->last_usermask)
+            free(user->na->last_usermask);
+
+        user->na->last_usermask =
+            smalloc(strlen(GetIdent(user)) + strlen(GetHost(user)) + 2);
+        sprintf(user->na->last_usermask, "%s@%s", GetIdent(user),
+                GetHost(user));
+    }
+    if (debug)
+        alog("debug: %s changes its username to %s", user->nick, username);
+}
+
+#endif
+
+/*************************************************************************/
+
+void set_umode(User * user, int ac, char **av)
+{
+    int add = 1;                /* 1 if adding modes, 0 if deleting */
+    char *modes = av[0];
+
+    ac--;
+
+    if (debug)
+        alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+    while (*modes) {
+
+        add ? (user->mode |= umodes[(int) *modes]) : (user->mode &=
+                                                      ~umodes[(int)
+                                                              *modes]);
+
+        switch (*modes++) {
+        case '+':
+            add = 1;
+            break;
+        case '-':
+            add = 0;
+            break;
+#if defined(IRC_ULTIMATE) || defined(IRC_ULTIMATE3)
+        case 'a':
+            if (add && !is_services_oper(user)) {
+                send_cmd(ServerName, "SVSMODE %s -a", user->nick);
+                user->mode &= ~UMODE_a;
+            }
+            break;
+        case 'P':
+            if (add && !is_services_admin(user)) {
+                send_cmd(ServerName, "SVSMODE %s -P", user->nick);
+                user->mode &= ~UMODE_P;
+            }
+            break;
+#endif
+#if defined(IRC_ULTIMATE)
+        case 'R':
+            if (add && !is_services_root(user)) {
+                send_cmd(ServerName, "SVSMODE %s -R", user->nick);
+                user->mode &= ~UMODE_R;
+            }
+            break;
+#endif
+#if defined(IRC_ULTIMATE3)
+        case 'Z':
+            if (add && !is_services_root(user)) {
+                send_cmd(ServerName, "SVSMODE %s -Z", user->nick);
+                user->mode &= ~UMODE_Z;
+            }
+            break;
+#endif
+        case 'd':
+            if (ac == 0) {
+#if !defined(IRC_ULTIMATE) && !defined(IRC_UNREAL)
+                alog("user: umode +d with no parameter (?) for user %s",
+                     user->nick);
+#endif
+                break;
+            }
+
+            ac--;
+            av++;
+            user->svid = strtoul(*av, NULL, 0);
+            break;
+        case 'o':
+            if (add) {
+                opcnt++;
+
+                if (WallOper)
+                    wallops(s_OperServ, "\2%s\2 is now an IRC operator.",
+                            user->nick);
+                display_news(user, NEWS_OPER);
+#if defined(IRC_PTLINK)
+                if (is_services_admin(user)) {
+                    send_cmd(ServerName, "SVSMODE %s +a", user->nick);
+                    user->mode |= UMODE_a;
+                }
+#endif
+#if defined(IRC_ULTIMATE) || defined(IRC_ULTIMATE3)
+                if (is_services_oper(user)) {
+                    send_cmd(ServerName, "SVSMODE %s +a", user->nick);
+                    user->mode |= UMODE_a;
+                }
+
+                if (is_services_admin(user)) {
+                    send_cmd(ServerName, "SVSMODE %s +P", user->nick);
+                    user->mode |= UMODE_P;
+                }
+#endif
+
+#ifdef IRC_ULTIMATE
+                if (is_services_root(user)) {
+                    send_cmd(ServerName, "SVSMODE %s +R", user->nick);
+                    user->mode |= UMODE_R;
+                }
+#endif
+#ifdef IRC_ULTIMATE3
+                if (is_services_root(user)) {
+                    send_cmd(ServerName, "SVSMODE %s +Z", user->nick);
+                    user->mode |= UMODE_Z;
+                }
+#endif
+            } else {
+                opcnt--;
+            }
+            break;
+        case 'r':
+            if (add && !nick_identified(user)) {
+                send_cmd(ServerName, "SVSMODE %s -r", user->nick);
+                user->mode &= ~UMODE_r;
+            }
+            break;
+#if defined(IRC_ULTIMATE) || defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_VIAGRA)
+        case 'x':
+            update_host(user);
+            break;
+#endif
+        }
+    }
+}
+
+/*************************************************************************/
+
+/* Remove and free a User structure. */
+
+static void delete_user(User * user)
+{
+    struct u_chanlist *c, *c2;
+    struct u_chaninfolist *ci, *ci2;
+
+    if (LogUsers) {
+#ifdef HAS_VHOST
+        alog("LOGUSERS: %s (%s@%s => %s) (%s) left the network (%s).",
+             user->nick, user->username, user->host,
+             (user->vhost ? user->vhost : "(none)"), user->realname,
+             user->server);
+#else
+        alog("LOGUSERS: %s (%s@%s) (%s) left the network (%s).",
+             user->nick, user->username, user->host,
+             user->realname, user->server);
+#endif
+    }
+
+    if (debug >= 2)
+        alog("debug: delete_user() called");
+    usercnt--;
+    if (is_oper(user))
+        opcnt--;
+    if (debug >= 2)
+        alog("debug: delete_user(): free user data");
+    free(user->username);
+    free(user->host);
+#ifdef HAS_VHOST
+    if (user->vhost)
+        free(user->vhost);
+#endif
+    free(user->realname);
+    free(user->server);
+    if (debug >= 2)
+        alog("debug: delete_user(): remove from channels");
+    c = user->chans;
+    while (c) {
+        c2 = c->next;
+        chan_deluser(user, c->chan);
+        free(c);
+        c = c2;
+    }
+    /* This called only here now */
+    cancel_user(user);
+    if (user->na)
+        user->na->u = NULL;
+    if (debug >= 2)
+        alog("debug: delete_user(): free founder data");
+    ci = user->founder_chans;
+    while (ci) {
+        ci2 = ci->next;
+        free(ci);
+        ci = ci2;
+    }
+    if (debug >= 2)
+        alog("debug: delete_user(): delete from list");
+    if (user->prev)
+        user->prev->next = user->next;
+    else
+        userlist[HASH(user->nick)] = user->next;
+    if (user->next)
+        user->next->prev = user->prev;
+    if (debug >= 2)
+        alog("debug: delete_user(): free user structure");
+    free(user);
+    if (debug >= 2)
+        alog("debug: delete_user() done");
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Return statistics.  Pointers are assumed to be valid. */
+
+void get_user_stats(long *nusers, long *memuse)
+{
+    long count = 0, mem = 0;
+    int i;
+    User *user;
+    struct u_chanlist *uc;
+    struct u_chaninfolist *uci;
+
+    for (i = 0; i < 1024; i++) {
+        for (user = userlist[i]; user; user = user->next) {
+            count++;
+            mem += sizeof(*user);
+            if (user->username)
+                mem += strlen(user->username) + 1;
+            if (user->host)
+                mem += strlen(user->host) + 1;
+#ifdef HAS_VHOST
+            if (user->vhost)
+                mem += strlen(user->vhost) + 1;
+#endif
+            if (user->realname)
+                mem += strlen(user->realname) + 1;
+            if (user->server)
+                mem += strlen(user->server) + 1;
+            for (uc = user->chans; uc; uc = uc->next)
+                mem += sizeof(*uc);
+            for (uci = user->founder_chans; uci; uci = uci->next)
+                mem += sizeof(*uci);
+        }
+    }
+    *nusers = count;
+    *memuse = mem;
+}
+
+/*************************************************************************/
+
+/* Find a user by nick.  Return NULL if user could not be found. */
+
+User *finduser(const char *nick)
+{
+    User *user;
+
+    if (debug >= 3)
+        alog("debug: finduser(%p)", nick);
+    user = userlist[HASH(nick)];
+    while (user && stricmp(user->nick, nick) != 0)
+        user = user->next;
+    if (debug >= 3)
+        alog("debug: finduser(%s) -> %p", nick, user);
+    return user;
+}
+
+/*************************************************************************/
+
+/* Iterate over all users in the user list.  Return NULL at end of list. */
+
+static User *current;
+static int next_index;
+
+User *firstuser(void)
+{
+    next_index = 0;
+    while (next_index < 1024 && current == NULL)
+        current = userlist[next_index++];
+    if (debug)
+        alog("debug: firstuser() returning %s",
+             current ? current->nick : "NULL (end of list)");
+    return current;
+}
+
+User *nextuser(void)
+{
+    if (current)
+        current = current->next;
+    if (!current && next_index < 1024) {
+        while (next_index < 1024 && current == NULL)
+            current = userlist[next_index++];
+    }
+    if (debug)
+        alog("debug: nextuser() returning %s",
+             current ? current->nick : "NULL (end of list)");
+    return current;
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Handle a server NICK command. */
+
+User *do_nick(const char *source, char *nick, char *username, char *host,
+              char *server, char *realname, time_t ts, uint32 svid, ...)
+{
+    User *user;
+
+    char *tmp = NULL;
+    NickAlias *old_na;          /* Old nick rec */
+    int nc_changed = 1;         /* Did nick core change? */
+    int status = 0;             /* Status to apply */
+    char mask[USERMAX + HOSTMAX + 2];
+
+    if (!*source) {
+#ifdef HAS_NICKIP
+        char ipbuf[16];
+        struct in_addr addr;
+        uint32 ip;
+#endif
+#ifdef HAS_VHOST
+        char *vhost = NULL;
+#endif
+#if defined(HAS_NICKIP) || defined(HAS_NICKVHOST)
+        va_list args;
+        va_start(args, svid);
+#endif
+
+#ifdef HAS_NICKIP
+        ip = va_arg(args, uint32);
+#endif
+
+#ifdef HAS_NICKVHOST
+        vhost = va_arg(args, char *);
+        if (!strcmp(vhost, "*")) {
+            vhost = NULL;
+            if (debug)
+                alog("debug: new user with no vhost in NICK command: %s",
+                     nick);
+        }
+#endif
+
+        /* This is a new user; create a User structure for it. */
+        if (debug)
+            alog("debug: new user: %s", nick);
+
+        if (LogUsers) {
+        /**
+	 * Ugly swap routine for Flop's bug :)
+ 	 **/
+            tmp = strchr(realname, '%');
+            while (tmp) {
+                *tmp = '-';
+                tmp = strchr(realname, '%');
+            }
+        /**
+	 * End of ugly swap
+	 **/
+
+#ifdef HAS_NICKIP
+            addr.s_addr = htonl(ip);
+            ntoa(addr, ipbuf, sizeof(ipbuf));
+#endif
+
+#ifdef HAS_NICKVHOST
+# ifdef HAS_NICKIP
+            alog("LOGUSERS: %s (%s@%s => %s) (%s) [%s] connected to the network (%s).", nick, username, host, vhost, realname, ipbuf, server);
+# else
+            alog("LOGUSERS: %s (%s@%s => %s) (%s) connected to the network (%s).", nick, username, host, vhost, realname, server);
+# endif
+#else
+# ifdef HAS_NICKIP
+            alog("LOGUSERS: %s (%s@%s) (%s) [%s] connected to the network (%s).", nick, username, host, realname, ipbuf, server);
+# else
+            alog("LOGUSERS: %s (%s@%s) (%s) connected to the network (%s).", nick, username, host, realname, server);
+# endif
+#endif
+        }
+
+        /* We used to ignore the ~ which a lot of ircd's use to indicate no
+         * identd response.  That caused channel bans to break, so now we
+         * just take what the server gives us.  People are still encouraged
+         * to read the RFCs and stop doing anything to usernames depending
+         * on the result of an identd lookup.
+         */
+
+        /* First check for AKILLs. */
+        /* DONT just return null if its an akill match anymore - yes its more efficent to, however, now that ircd's are
+         * starting to use things like E/F lines, we cant be 100% sure the client will be removed from the network :/
+         * as such, create a user_struct, and if the client is removed, we'll delete it again when the QUIT notice
+         * comes in from the ircd.
+         **/
+        if (check_akill(nick, username, host,
+#ifdef HAS_NICKVHOST
+                        vhost,
+#else
+                        NULL,
+#endif
+#ifdef HAS_NICKIP
+                        ipbuf)) {
+#else
+                        NULL)) {
+#endif
+/*            return NULL; */
+        }
+
+/**
+ * DefCon AKILL system, if we want to akill all connecting user's here's where to do it
+ * then force check_akill again on them...
+ **/
+        if (checkDefCon(DEFCON_AKILL_NEW_CLIENTS)) {
+            strncpy(mask, "*@", 3);
+            strncat(mask, host, HOSTMAX);
+            alog("DEFCON: adding akill for %s", mask);
+            add_akill(NULL, mask, s_OperServ,
+                      time(NULL) + dotime(DefConAKILL),
+                      DefConAkillReason ? DefConAkillReason :
+                      "DEFCON AKILL");
+            if (check_akill(nick, username, host,
+#ifdef HAS_NICKVHOST
+                            vhost,
+#else
+                            NULL,
+#endif
+#ifdef HAS_NICKIP
+                            ipbuf)) {
+#else
+                            NULL)) {
+#endif
+/*            return NULL; */
+            }
+        }
+#ifdef IRC_BAHAMUT
+        /* Next for SGLINEs */
+        if (check_sgline(nick, realname))
+            return NULL;
+#endif
+
+        /* And for SQLINEs */
+        if (check_sqline(nick, 0))
+            return NULL;
+
+#ifndef STREAMLINED
+        /* Now check for session limits */
+        if (LimitSessions && !add_session(nick, host))
+            return NULL;
+#endif
+
+        /* And finally, for proxy ;) */
+#ifdef USE_THREADS
+# ifdef HAS_NICKIP
+        if (ProxyDetect && proxy_check(nick, host, ip))
+# else
+        if (ProxyDetect && proxy_check(nick, host, 0))
+# endif
+            return NULL;
+#endif
+
+        /* Allocate User structure and fill it in. */
+        user = new_user(nick);
+        user->username = sstrdup(username);
+        user->host = sstrdup(host);
+        user->server = sstrdup(server);
+        user->realname = sstrdup(realname);
+        user->timestamp = ts;
+        user->my_signon = time(NULL);
+
+#ifdef HAS_VHOST
+        user->vhost = vhost ? sstrdup(vhost) : sstrdup(host);
+#endif
+
+        if (CheckClones) {
+            /* Check to see if it looks like clones. */
+            check_clones(user);
+        }
+
+        if (svid == 0) {
+            display_news(user, NEWS_LOGON);
+            display_news(user, NEWS_RANDOM);
+        }
+
+        if (svid == ts && user->na) {
+            /* Timestamp and svid match, and nick is registered; automagically identify the nick */
+            user->svid = svid;
+            user->na->status |= NS_IDENTIFIED;
+            check_memos(user);
+            nc_changed = 0;
+        } else if (svid != 1) {
+            /* Resets the svid because it doesn't match */
+            user->svid = 1;
+#ifdef IRC_BAHAMUT
+            send_cmd(ServerName, "SVSMODE %s %lu +d 1", user->nick,
+                     user->timestamp);
+#else
+#ifndef IRC_PTLINK
+            send_cmd(ServerName, "SVSMODE %s +d 1", user->nick);
+#endif
+#endif
+        } else {
+            user->svid = 1;
+        }
+
+    } else {
+        /* An old user changing nicks. */
+        user = finduser(source);
+        if (!user) {
+            alog("user: NICK from nonexistent nick %s", source);
+            return NULL;
+        }
+        user->isSuperAdmin = 0; /* Dont let people nick change and stay SuperAdmins */
+        if (debug)
+            alog("debug: %s changes nick to %s", source, nick);
+
+        if (LogUsers) {
+#ifdef HAS_VHOST
+            alog("LOGUSERS: %s (%s@%s => %s) (%s) changed his nick to %s (%s).", user->nick, user->username, user->host, (user->vhost ? user->vhost : "(none)"), user->realname, nick, user->server);
+#else
+            alog("LOGUSERS: %s (%s@%s) (%s) changed his nick to %s (%s).",
+                 user->nick, user->username, user->host,
+                 user->realname, nick, user->server);
+#endif
+        }
+
+        user->timestamp = ts;
+
+        if (stricmp(nick, user->nick) == 0) {
+            /* No need to redo things */
+            change_user_nick(user, nick);
+            nc_changed = 0;
+        } else {
+            /* Update this only if nicks aren't the same */
+            user->my_signon = time(NULL);
+
+            old_na = user->na;
+            if (old_na) {
+                if (nick_recognized(user))
+                    user->na->last_seen = time(NULL);
+                status = old_na->status & NS_TRANSGROUP;
+                cancel_user(user);
+            }
+
+            change_user_nick(user, nick);
+
+            if ((old_na ? old_na->nc : NULL) ==
+                (user->na ? user->na->nc : NULL))
+                nc_changed = 0;
+
+            if (!nc_changed && (user->na))
+                user->na->status |= status;
+            else {
+#if !defined(IRC_BAHAMUT) && !defined(IRC_PTLINK)
+                /* Because on Bahamut it would be already -r */
+                change_user_mode(user, "-r+d", "1");
+#else
+                change_user_mode(user, "+d", "1");
+#endif
+            }
+        }
+
+        if (!is_oper(user) && check_sqline(user->nick, 1))
+            return NULL;
+
+    }                           /* if (!*source) */
+
+    if (nc_changed || !nick_recognized(user)) {
+        if (validate_user(user))
+            check_memos(user);
+    } else {
+        if (nick_identified(user)) {
+            user->na->last_seen = time(NULL);
+
+            if (user->na->last_usermask)
+                free(user->na->last_usermask);
+            user->na->last_usermask =
+                smalloc(strlen(GetIdent(user)) + strlen(GetHost(user)) +
+                        2);
+            sprintf(user->na->last_usermask, "%s@%s", GetIdent(user),
+                    GetHost(user));
+
+#ifdef IRC_PTLINK
+            change_user_mode(user, "+r", NULL);
+#endif
+
+#if !defined(IRC_BAHAMUT) && !defined(IRC_PTLINK)
+            if (user->svid != user->timestamp) {
+                char tsbuf[16];
+                snprintf(tsbuf, sizeof(tsbuf), "%lu", user->timestamp);
+                change_user_mode(user, "+rd", tsbuf);
+            } else {
+                change_user_mode(user, "+r", NULL);
+            }
+#endif
+
+
+            alog("%s: %s!%s@%s automatically identified for nick %s",
+                 s_NickServ, user->nick, user->username, GetHost(user),
+                 user->nick);
+        }
+    }
+
+/* Bahamut sets -r on every nick changes, so we must test it even if nc_changed == 0 */
+#ifdef IRC_BAHAMUT
+    if (nick_identified(user)) {
+        if (user->svid != user->timestamp) {
+            char tsbuf[16];
+            snprintf(tsbuf, sizeof(tsbuf), "%lu", user->timestamp);
+            change_user_mode(user, "+rd", tsbuf);
+        } else {
+            change_user_mode(user, "+r", NULL);
+        }
+    }
+#endif
+
+    return user;
+}
+
+/*************************************************************************/
+
+/* Handle a MODE command for a user.
+ *	av[0] = nick to change mode for
+ *	av[1] = modes
+ */
+
+void do_umode(const char *source, int ac, char **av)
+{
+    User *user;
+
+    if (stricmp(source, av[0]) != 0) {
+        alog("user: MODE %s %s from different nick %s!", av[0], av[1],
+             source);
+        wallops(NULL, "%s attempted to change mode %s for %s", source,
+                av[1], av[0]);
+        return;
+    }
+
+    user = finduser(source);
+    if (!user) {
+        alog("user: MODE %s for nonexistent nick %s: %s", av[1], source,
+             merge_args(ac, av));
+        return;
+    }
+
+    set_umode(user, ac - 1, &av[1]);
+}
+
+/*************************************************************************/
+
+/* Handle a QUIT command.
+ *	av[0] = reason
+ */
+
+void do_quit(const char *source, int ac, char **av)
+{
+    User *user;
+    NickAlias *na;
+
+    user = finduser(source);
+    if (!user) {
+        alog("user: QUIT from nonexistent user %s: %s", source,
+             merge_args(ac, av));
+        return;
+    }
+    if (debug)
+        alog("debug: %s quits", source);
+    if ((na = user->na) && (!(na->status & NS_VERBOTEN))
+        && (na->status & (NS_IDENTIFIED | NS_RECOGNIZED))) {
+        na->last_seen = time(NULL);
+        if (na->last_quit)
+            free(na->last_quit);
+        na->last_quit = *av[0] ? sstrdup(av[0]) : NULL;
+    }
+#ifndef STREAMLINED
+    if (LimitSessions)
+        del_session(user->host);
+#endif
+    delete_user(user);
+}
+
+/*************************************************************************/
+
+/* Handle a KILL command.
+ *	av[0] = nick being killed
+ *	av[1] = reason
+ */
+
+void do_kill(const char *source, int ac, char **av)
+{
+    User *user;
+    NickAlias *na;
+
+    user = finduser(av[0]);
+    if (!user)
+        return;
+    if (debug)
+        alog("debug: %s killed", av[0]);
+    if ((na = user->na) && (!(na->status & NS_VERBOTEN))
+        && (na->status & (NS_IDENTIFIED | NS_RECOGNIZED))) {
+        na->last_seen = time(NULL);
+        if (na->last_quit)
+            free(na->last_quit);
+        na->last_quit = *av[1] ? sstrdup(av[1]) : NULL;
+
+    }
+#ifndef STREAMLINED
+    if (LimitSessions)
+        del_session(user->host);
+#endif
+    delete_user(user);
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+#if defined(IRC_ULTIMATE) || defined(IRC_ULTIMATE3)
+
+/* Is the given user protected from kicks and negative mode changes? */
+
+int is_protected(User * user)
+{
+    return (user->mode & UMODE_p);
+}
+#endif
+
+/*************************************************************************/
+
+/* Is the given nick an oper? */
+
+int is_oper(User * user)
+{
+    return (user->mode & UMODE_o);
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+#if defined (IRC_ULTIMATE) || defined(IRC_ULTIMATE3) || defined(IRC_UNREAL) || defined(IRC_VIAGRA) || defined(IRC_HYBRID)
+/* Is the given user ban-excepted? */
+int is_excepted(ChannelInfo * ci, User * user)
+{
+    int count, i;
+    int isexcepted = 0;
+    char **excepts;
+
+    if (!ci->c)
+        return 0;
+
+    count = ci->c->exceptcount;
+    excepts = scalloc(sizeof(char *) * count, 1);
+    memcpy(excepts, ci->c->excepts, sizeof(char *) * count);
+
+    for (i = 0; i < count; i++) {
+        if (match_usermask(excepts[i], user)) {
+            isexcepted = 1;
+        }
+    }
+    free(excepts);
+    return isexcepted;
+}
+
+/*************************************************************************/
+
+/* Is the given MASK ban-excepted? */
+int is_excepted_mask(ChannelInfo * ci, char *mask)
+{
+    int count, i;
+    int isexcepted = 0;
+    char **excepts;
+
+    if (!ci->c)
+        return 0;
+
+    count = ci->c->exceptcount;
+    excepts = scalloc(sizeof(char *) * count, 1);
+    memcpy(excepts, ci->c->excepts, sizeof(char *) * count);
+
+    for (i = 0; i < count; i++) {
+        if (match_wild_nocase(excepts[i], mask)) {
+            isexcepted = 1;
+        }
+    }
+    free(excepts);
+    return isexcepted;
+}
+
+#endif
+/*************************************************************************/
+
+/* Does the user's usermask match the given mask (either nick!user@host or
+ * just user@host)?
+ */
+
+int match_usermask(const char *mask, User * user)
+{
+    char *mask2 = sstrdup(mask);
+    char *nick, *username, *host;
+    int result;
+
+    if (strchr(mask2, '!')) {
+        nick = strtok(mask2, "!");
+        username = strtok(NULL, "@");
+    } else {
+        nick = NULL;
+        username = strtok(mask2, "@");
+    }
+    host = strtok(NULL, "");
+    if (!username || !host) {
+        free(mask2);
+        return 0;
+    }
+
+    if (nick) {
+        result = match_wild_nocase(nick, user->nick)
+            && match_wild_nocase(username, user->username)
+            && (match_wild_nocase(host, user->host)
+#ifdef HAS_VHOST
+                || match_wild_nocase(host, user->vhost)
+#endif
+            );
+    } else {
+        result = match_wild_nocase(username, user->username)
+            && (match_wild_nocase(host, user->host)
+#ifdef HAS_VHOST
+                || match_wild_nocase(host, user->vhost)
+#endif
+            );
+    }
+
+    free(mask2);
+    return result;
+}
+
+/*************************************************************************/
+
+/* Split a usermask up into its constitutent parts.  Returned strings are
+ * malloc()'d, and should be free()'d when done with.  Returns "*" for
+ * missing parts.
+ */
+
+void split_usermask(const char *mask, char **nick, char **user,
+                    char **host)
+{
+    char *mask2 = sstrdup(mask);
+
+    *nick = strtok(mask2, "!");
+    *user = strtok(NULL, "@");
+    *host = strtok(NULL, "");
+    /* Handle special case: mask == user@host */
+    if (*nick && !*user && strchr(*nick, '@')) {
+        *nick = NULL;
+        *user = strtok(mask2, "@");
+        *host = strtok(NULL, "");
+    }
+    if (!*nick)
+        *nick = "*";
+    if (!*user)
+        *user = "*";
+    if (!*host)
+        *host = "*";
+    *nick = sstrdup(*nick);
+    *user = sstrdup(*user);
+    *host = sstrdup(*host);
+    free(mask2);
+}
+
+/*************************************************************************/
+
+/* Given a user, return a mask that will most likely match any address the
+ * user will have from that location.  For IP addresses, wildcards the
+ * appropriate subnet mask (e.g. 35.1.1.1 -> 35.*; 128.2.1.1 -> 128.2.*);
+ * for named addresses, wildcards the leftmost part of the name unless the
+ * name only contains two parts.  If the username begins with a ~, delete
+ * it.  The returned character string is malloc'd and should be free'd
+ * when done with.
+ */
+
+char *create_mask(User * u)
+{
+    char *mask, *s, *end;
+    int ulen = strlen(GetIdent(u));
+
+    /* Get us a buffer the size of the username plus hostname.  The result
+     * will never be longer than this (and will often be shorter), thus we
+     * can use strcpy() and sprintf() safely.
+     */
+    end = mask = smalloc(ulen + strlen(GetHost(u)) + 3);
+    end += sprintf(end, "%s%s@",
+                   (ulen <
+                    (*(GetIdent(u)) ==
+                     '~' ? USERMAX + 1 : USERMAX) ? "*" : ""),
+                   (*(GetIdent(u)) ==
+                    '~' ? GetIdent(u) + 1 : GetIdent(u)));
+
+    if (strspn(GetHost(u), "0123456789.") == strlen(GetHost(u))
+        && (s = strchr(GetHost(u), '.'))
+        && (s = strchr(s + 1, '.'))
+        && (s = strchr(s + 1, '.'))
+        && (!strchr(s + 1, '.'))) {     /* IP addr */
+        s = sstrdup(GetHost(u));
+        *strrchr(s, '.') = 0;
+
+        sprintf(end, "%s.*", s);
+        free(s);
+    } else {
+        if ((s = strchr(GetHost(u), '.')) && strchr(s + 1, '.')) {
+            s = sstrdup(strchr(GetHost(u), '.') - 1);
+            *s = '*';
+            strcpy(end, s);
+            free(s);
+        } else {
+            strcpy(end, GetHost(u));
+        }
+    }
+    return mask;
+}
+
+/*************************************************************************/
