]> jfr.im git - irc/evilnet/x3.git/blobdiff - src/proto-p10.c
Fixed an issue with OPCHAN and channels using offchannel
[irc/evilnet/x3.git] / src / proto-p10.c
index 948a58e8936db91ad71a89fc897552c5692ff825..140e2d5632ad5f4f174d405f240df6174492ad26 100644 (file)
 #define CMD_SETTIME             "SETTIME"
 #define CMD_SHUN               "SHUN"
 #define CMD_SILENCE             "SILENCE"
+#define CMD_SNO                 "SNO"
 #define CMD_SQUERY              "SQUERY"
 #define CMD_SQUIT               "SQUIT"
 #define CMD_STATS               "STATS"
 #define CMD_SVSJOIN             "SVSJOIN"
 #define CMD_SVSNICK             "SVSNICK"
 #define CMD_SVSPART             "SVSPART"
+#define CMD_SVSQUIT             "SVSQUIT"
 #define CMD_SWHOIS              "SWHOIS"
 #define CMD_TIME                "TIME"
 #define CMD_TOPIC               "TOPIC"
 #define TOK_SETTIME             "SE"
 #define TOK_SHUN               "SU"
 #define TOK_SILENCE             "U"
+#define TOK_SNO                 "SNO"
 #define TOK_SQUERY              "SQUERY"
 #define TOK_SQUIT               "SQ"
 #define TOK_STATS               "R"
 #define TOK_SVSJOIN             "SJ"
 #define TOK_SVSNICK             "SN"
 #define TOK_SVSPART             "SP"
+#define TOK_SVSQUIT             "SX"
 #define TOK_SWHOIS              "SW"
 #define TOK_TIME                "TI"
 #define TOK_TOPIC               "T"
 #define P10_SETTIME             TYPE(SETTIME)
 #define P10_SHUN               TYPE(SHUN)
 #define P10_SILENCE             TYPE(SILENCE)
+#define P10_SNO                 TYPE(SNO)
 #define P10_SQUERY              TYPE(SQUERY)
 #define P10_SQUIT               TYPE(SQUIT)
 #define P10_STATS               TYPE(STATS)
 #define P10_SVSJOIN             TYPE(SVSJOIN)
 #define P10_SVSNICK             TYPE(SVSNICK)
 #define P10_SVSPART             TYPE(SVSPART)
+#define P10_SVSQUIT            TYPE(SVSQUIT)
 #define P10_SWHOIS              TYPE(SWHOIS)
 #define P10_TIME                TYPE(TIME)
 #define P10_TOPIC               TYPE(TOPIC)
@@ -477,7 +483,7 @@ irc_server(struct server *srv)
     }
 }
 
-static void
+void
 irc_p10_pton(irc_in_addr_t *ip, const char *input)
 {
     if (strlen(input) == 6) {
@@ -504,7 +510,7 @@ irc_p10_pton(irc_in_addr_t *ip, const char *input)
     }
 }
 
-static void
+void
 irc_p10_ntop(char *output, const irc_in_addr_t *ip)
 {
     if (!irc_in_addr_is_valid(*ip)) {
@@ -556,7 +562,7 @@ void
 irc_user(struct userNode *user)
 {
     char b64ip[25];
-    if (!user || IsDummy(user))
+    if (!user)
         return;
     irc_p10_ntop(b64ip, &user->ip);
     if (user->modes) {
@@ -578,16 +584,23 @@ irc_user(struct userNode *user)
             modes[modelen++] = 'd';
         if (IsGlobal(user))
             modes[modelen++] = 'g';
+        // sethost - reed/apples
+        // if (IsHelperIrcu(user))
         if (IsSetHost(user))
             modes[modelen++] = 'h';
         if (IsFakeHost(user))
             modes[modelen++] = 'f';
         if (IsHiddenHost(user))
             modes[modelen++] = 'x';
-        if (IsNoChan(user))
+        if (IsBotM(user))
+            modes[modelen++] = 'B';
+        if (IsHideChans(user))
             modes[modelen++] = 'n';
-        if (IsNoIdle(user))
+        if (IsHideIdle(user))
             modes[modelen++] = 'I';
+        if (IsXtraOp(user))
+            modes[modelen++] = 'X';
+
         modes[modelen] = 0;
 
         /* we don't need to put the + in modes because it's in the format string. */
@@ -693,47 +706,22 @@ irc_wallops(const char *format, ...)
     putsock("%s " P10_WALLOPS " :%s", self->numeric, buffer);
 }
 
-static int
-deliver_to_dummy(struct userNode *source, struct userNode *dest, const char *message, int type)
-{
-    unsigned int num;
-
-    if (!dest || !IsDummy(dest) || !IsLocal(dest))
-        return 0;
-    num = dest->num_local;
-    switch (type) {
-    default:
-        if ((num < num_notice_funcs) && notice_funcs[num])
-            notice_funcs[num](source, dest, message, 0);
-        break;
-    case 1:
-        if ((num < num_privmsg_funcs) && privmsg_funcs[num])
-            privmsg_funcs[num](source, dest, message, 0);
-        break;
-    }
-    return 1;
-}
 
 void
 irc_notice(struct userNode *from, const char *to, const char *message)
 {
-    if (to[0] == '#' || to[0] == '$'
-        || !deliver_to_dummy(from, GetUserN(to), message, 0))
     putsock("%s " P10_NOTICE " %s :%s", from->numeric, to, message);
 }
 
 void
 irc_notice_user(struct userNode *from, struct userNode *to, const char *message)
 {
-    if (!deliver_to_dummy(from, to, message, 0))
     putsock("%s " P10_NOTICE " %s :%s", from->numeric, to->numeric, message);
 }
 
 void
 irc_privmsg(struct userNode *from, const char *to, const char *message)
 {
-    if (to[0] == '#' || to[0] == '$'
-        || !deliver_to_dummy(from, GetUserN(to), message, 1))
     putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to, message);
 }
 
@@ -827,21 +815,13 @@ irc_introduce(const char *passwd)
 void
 irc_gline(struct server *srv, struct gline *gline, int silent)
 {
-    if (gline->lastmod)
-        putsock("%s " P10_GLINE " %s +%s %ld %ld :%s",
-                self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, gline->lastmod, gline->reason);
-    else
-    putsock("%s " P10_GLINE " %s +%s %ld :%s<%s> %s",
-            self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, silent ? "AUTO " : "", gline->issuer, gline->reason);
+    putsock("%s " P10_GLINE " %s +%s %ld %ld :%s<%s> %s",
+            self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, now, silent ? "AUTO " : "", gline->issuer, gline->reason);
 }
 
 void
 irc_shun(struct server *srv, struct shun *shun)
 {
-    if (shun->lastmod)
-        putsock("%s " P10_SHUN " %s +%s %ld %ld :%s",
-                self->numeric, (srv ? srv->numeric : "*"), shun->target, shun->expires-now, shun->lastmod, shun->reason);
-    else
     putsock("%s " P10_SHUN " %s +%s %ld :<%s> %s",
             self->numeric, (srv ? srv->numeric : "*"), shun->target, shun->expires-now, shun->issuer, shun->reason);
 }
@@ -1052,6 +1032,12 @@ irc_svspart(struct userNode *from, struct userNode *who, struct chanNode *to)
     putsock("%s " P10_SVSPART " %s %s", from->uplink->numeric, who->numeric, to->name);
 }
 
+void
+irc_svsquit(struct userNode *from, struct userNode *who, char *reason)
+{
+    putsock("%s " P10_SVSQUIT " %s :%s", from->uplink->numeric, who->numeric, reason);
+}
+
 void
 irc_kick(struct userNode *who, struct userNode *target, struct chanNode *channel, const char *msg)
 {
@@ -1221,8 +1207,6 @@ static CMD_FUNC(cmd_whois)
 {
     struct userNode *from;
     struct userNode *who;
-    char buf[MAXLEN];
-    unsigned int i, mlen, len;
 
     if (argc < 3)
         return 0;
@@ -1234,70 +1218,17 @@ static CMD_FUNC(cmd_whois)
         irc_numeric(from, ERR_NOSUCHNICK, "%s@%s :No such nick", argv[2], self->name);
         return 1;
     }
-
-    if (IsFakeHost(who) && IsHiddenHost(who))
-        irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->fakehost, who->info);
-    else if (IsHiddenHost(who) && who->handle_info && hidden_host_suffix)
-        irc_numeric(from, RPL_WHOISUSER, "%s %s %s.%s * :%s", who->nick, who->ident, who->handle_info->handle, hidden_host_suffix, who->info);
-    else
-        irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->hostname, who->info);
-
-    if ((!IsService(who) && !IsNoChan(who)) || (from == who)) {
-        struct modeNode *mn;
-        mlen = strlen(self->name) + strlen(from->nick) + 12 + strlen(who->nick);
-        len = 0;
-        *buf = '\0';
-        for (i = who->channels.used; i > 0; )
-        {
-            mn = who->channels.list[--i];
-
-            if (!IsOper(from) && (mn->channel->modes & (MODE_PRIVATE | MODE_SECRET)) && !GetUserMode(mn->channel, from))
-                continue;
-
-            if (len + strlen(mn->channel->name) + mlen > MAXLEN - 5)
-            {
-                irc_numeric(from, RPL_WHOISCHANNELS, "%s :%s", who->nick, buf);
-                *buf = '\0';
-                len = 0;
-            }
-
-            if (IsDeaf(who))
-                *(buf + len++) = '-';
-            if ((mn->channel->modes & (MODE_PRIVATE | MODE_SECRET)) && !GetUserMode(mn->channel, from))
-                *(buf + len++) = '*';
-            if (mn->modes & MODE_CHANOP)
-                *(buf + len++) = '@';
-            else if (mn->modes & MODE_VOICE)
-                *(buf + len++) = '+';
-
-            if (len)
-                *(buf + len) = '\0';
-            strcpy(buf + len, mn->channel->name);
-            len += strlen(mn->channel->name);
-            strcat(buf + len, " ");
-            len++;
-        }
-        if (buf[0] != '\0')
-            irc_numeric(from, RPL_WHOISCHANNELS, "%s :%s", who->nick, buf);
+    if (IsHiddenHost(who) && !IsOper(from)) {
+        /* Just stay quiet. */
+        return 1;
     }
-
-    if (his_servername && his_servercomment && !IsOper(from) && from != who)
+    irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->hostname, who->info);
+    if (his_servername && his_servercomment)
         irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, his_servername, his_servercomment);
     else
         irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, who->uplink->name, who->uplink->description);
-
-    if (IsAway(who))
-        irc_numeric(from, RPL_AWAY, "%s :Away", who->nick);
-
     if (IsOper(who))
-        irc_numeric(from, RPL_WHOISOPERATOR, "%s :%s", who->nick, IsLocal(who) ? "is a megalomaniacal power hungry tyrant" : "is an IRC Operator");
-    if (who->handle_info)
-        irc_numeric(from, RPL_WHOISACCOUNT, "%s %s :is logged in as", who->nick, who->handle_info->handle);
-    if (IsHiddenHost(who) && who->handle_info && (IsOper(from) || from == who))
-        irc_numeric(from, RPL_WHOISACTUALLY, "%s %s@%s %s :Actual user@host, Actual IP", who->nick, who->ident, who->hostname, irc_ntoa(&who->ip));
-    if (IsLocal(who) && !IsService(who) && (!IsNoIdle(who) || IsOper(from) || from == who))
-        irc_numeric(from, RPL_WHOISIDLE, "%s %ld %ld :seconds idle, signon time", who->nick, now - who->idle_since, who->timestamp);
-
+        irc_numeric(from, RPL_WHOISOPERATOR, "%s :is a megalomaniacal power hungry tyrant", who->nick);
     irc_numeric(from, RPL_ENDOFWHOIS, "%s :End of /WHOIS list", who->nick);
     return 1;
 }
@@ -1407,7 +1338,7 @@ static CMD_FUNC(cmd_rping)
     struct server *dest;
 
     if (!(dest = GetServerN(argv[1])))
-        return 0;
+        return 1; /* if its a jupe or something, return 1 so its silently ignored */
 
     if (dest == self)
         irc_rpong(argv[2], argv[3], argv[4], argv[5]);
@@ -1572,7 +1503,22 @@ static CMD_FUNC(cmd_account)
     
     if(!strcmp(argv[2],"C"))
     {
-        if((hi = loc_auth(argv[4], argv[5])))
+        if((hi = loc_auth(argv[4], argv[5], NULL)))
+        {
+            /* Return a AC A */
+            putsock("%s " P10_ACCOUNT " %s A %s %lu", self->numeric, server->numeric , argv[3], hi->registered);
+
+        }
+        else
+        {
+            /* Return a AC D */
+            putsock("%s " P10_ACCOUNT " %s D %s", self->numeric, server->numeric , argv[3]);
+        }
+        return 1;
+    }
+    else if(!strcmp(argv[2],"H")) /* New enhanced (host) version of C */
+    {
+        if((hi = loc_auth(argv[5], argv[6], argv[4] )))
         {
             /* Return a AC A */
             putsock("%s " P10_ACCOUNT " %s A %s %lu", self->numeric, server->numeric , argv[3], hi->registered);
@@ -1617,7 +1563,8 @@ static struct {
   P(BADCHAN),        P(LOCAL_BADCHAN),  P(SEE_CHAN),      P(PROPAGATE),
   P(DISPLAY),        P(SEE_OPERS),      P(WIDE_GLINE),    P(FORCE_OPMODE),
   P(FORCE_LOCAL_OPMODE), P(REMOTEREHASH), P(CHECK), P(SEE_SECRET_CHAN),
-  P(SHUN),           P(LOCAL_SHUN),     P(WIDE_SHUN),
+  P(SHUN),           P(LOCAL_SHUN),     P(WIDE_SHUN),     P(ZLINE),
+  P(LOCAL_ZLINE),    P(WIDE_ZLINE),     P(LIST_CHAN),
 #undef P
   { 0, 0 }
 };
@@ -1723,6 +1670,7 @@ static CMD_FUNC(cmd_burst)
     static char exemptlist[MAXLEN], banlist[MAXLEN];
     unsigned int next = 3, res = 1;
     int ctype = 0, echeck = 0, bcheck = 0;
+    struct chanData *cData;
     struct chanNode *cNode;
     struct userNode *un;
     struct modeNode *mNode;
@@ -1748,8 +1696,6 @@ static CMD_FUNC(cmd_burst)
                 if ((*pos == 'k') || (*pos == 'l') || (*pos == 'A')
                     || (*pos == 'U'))
                     n_modes++;
-            if (next + n_modes > argc)
-                n_modes = argc - next;
             unsplit_string(argv+next, n_modes, modes);
             next += n_modes;
             break;
@@ -1808,6 +1754,15 @@ static CMD_FUNC(cmd_burst)
         irc_burst(cNode);
     }
     cNode = AddChannel(argv[1], in_timestamp, modes, banlist, exemptlist);
+    cData = cNode->channel_info;
+
+    if (!cData) {
+        if (cNode->modes & MODE_REGISTERED) {
+            irc_join(opserv, cNode);
+            irc_mode(opserv, cNode, "-z");
+            irc_part(opserv, cNode, "");
+        }
+    }
 
     /* Burst channel members in now. */
     for (user = members, sep = *members, mode = 0; sep; user = end) {
@@ -1872,13 +1827,32 @@ static CMD_FUNC(cmd_mark)
         /* DNSBL_DATA name */
         target = GetUserH(argv[1]);
         if(!target) {
-            log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose mark is changing.", argv[1]);
+            log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose dnsbl mark is changing.", argv[1]);
             return 0;
         }
         target->mark = strdup(argv[3]);
         return 1;
         
     }
+    else if(!strcasecmp(argv[2], "CVERSION")) {
+        /* DNSBL_DATA name */
+        target = GetUserH(argv[1]);
+        if(!target) {
+            log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose version mark is changing.", argv[1]);
+            return 0;
+        }
+
+        char *version = unsplit_string(argv + 3, argc - 3, NULL);
+        if(!version)
+            version = "";
+
+        target->version_reply = strdup(version);
+
+        if(match_ircglob(version, "WebTV;*"))
+            target->no_notice = true; /* webbies cant see notices */
+
+        return 1;
+    }
     /* unknown type of mark */
     return 1;
 }
@@ -2068,21 +2042,17 @@ static CMD_FUNC(cmd_num_topic)
 
 static CMD_FUNC(cmd_num_gline)
 {
-    time_t lastmod;
     if (argc < 6)
         return 0;
-    lastmod = (argc > 5) ? strtoul(argv[5], NULL, 0) : 0;
-    gline_add(origin, argv[3], atoi(argv[4])-now, argv[argc - 1], now, lastmod, 0, 0);
+    gline_add(origin, argv[3], atoi(argv[4])-now, argv[5], now, 0, 0);
     return 1;
 }
 
 static CMD_FUNC(cmd_num_shun)
 {
-    time_t lastmod;
     if (argc < 6)
         return 0;
-    lastmod = (argc > 5) ? strtoul(argv[5], NULL, 0) : 0;
-    shun_add(origin, argv[3], atoi(argv[4])-now, argv[argc - 1], now, lastmod, 0);
+    shun_add(origin, argv[3], atoi(argv[4])-now, argv[5], now, 0);
     return 1;
 }
 
@@ -2124,6 +2094,19 @@ static CMD_FUNC(cmd_kill)
     return 1;
 }
 
+static CMD_FUNC(cmd_part)
+{
+    struct userNode *user;
+
+    if (argc < 2)
+        return 0;
+    user = GetUserH(origin);
+    if (!user)
+        return 0;
+    parse_foreach(argv[1], part_helper, NULL, NULL, NULL, user);
+    return 1;
+}
+
 static CMD_FUNC(cmd_svspart)
 {
     struct userNode *user;
@@ -2219,7 +2202,7 @@ static CMD_FUNC(cmd_squit)
 static CMD_FUNC(cmd_privmsg)
 {
     struct privmsg_desc pd;
-    if (argc < 3)
+    if (argc != 3)
         return 0;
     pd.user = GetUserH(origin);
     if (!pd.user || (IsGagged(pd.user) && !IsOper(pd.user)))
@@ -2237,7 +2220,7 @@ static CMD_FUNC(cmd_privmsg)
         return 1; /* Silently Ignore */
 
     pd.is_notice = 0;
-    pd.text = argv[argc - 1];
+    pd.text = argv[2];
     parse_foreach(argv[1], privmsg_chan_helper, NULL, privmsg_user_helper, privmsg_invalid, &pd);
 
     return 1;
@@ -2249,7 +2232,7 @@ static CMD_FUNC(cmd_notice)
     struct server *srv;
     int nuser = 0;
 
-    if (argc < 3)
+    if (argc != 3)
         return 0;
 
     pd.user = GetUserH(origin);
@@ -2259,7 +2242,7 @@ static CMD_FUNC(cmd_notice)
     }
     else {
         pd.is_notice = 1;
-        pd.text = argv[argc - 1];
+        pd.text = argv[2];
         parse_foreach(argv[1], privmsg_chan_helper, NULL, privmsg_user_helper, privmsg_invalid, &pd);
     }
 
@@ -2305,15 +2288,12 @@ static CMD_FUNC(cmd_away)
 
 static CMD_FUNC(cmd_gline)
 {
-    time_t lastmod;
-
     if (argc < 3)
         return 0;
     if (argv[2][0] == '+') {
         if (argc < 5)
             return 0;
-        lastmod = (argc > 5) ? strtoul(argv[5], NULL, 0) : 0;
-        gline_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, lastmod, 0, 0);
+        gline_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, 0, 0);
         return 1;
     } else if (argv[2][0] == '-') {
         gline_remove(argv[2]+1, 0);
@@ -2324,14 +2304,12 @@ static CMD_FUNC(cmd_gline)
 
 static CMD_FUNC(cmd_shun)
 {
-    time_t lastmod;
     if (argc < 3)
         return 0;
     if (argv[2][0] == '+') {
         if (argc < 5)
             return 0;
-        lastmod = (argc > 5) ? strtoul(argv[5], NULL, 0) : 0;
-        shun_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, lastmod, 0);
+        shun_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, 0);
         return 1;
     } else if (argv[2][0] == '-') {
         shun_remove(argv[2]+1, 0);
@@ -2368,16 +2346,12 @@ parse_cleanup(void)
     unsigned int nn;
     free(of_list);
     free(privmsg_funcs);
-    num_privmsg_funcs = 0;
     free(notice_funcs);
-    num_notice_funcs = 0;
     free(mcf_list);
     dict_delete(irc_func_dict);
     for (nn=0; nn<dead_users.used; nn++)
         free_user(dead_users.list[nn]);
     userList_clean(&dead_users);
-    free(his_servername);
-    free(his_servercomment);
 }
 
 static void
@@ -2511,6 +2485,8 @@ init_parse(void)
     dict_insert(irc_func_dict, TOK_VERSION, cmd_version);
     dict_insert(irc_func_dict, CMD_ADMIN, cmd_admin);
     dict_insert(irc_func_dict, TOK_ADMIN, cmd_admin);
+    dict_insert(irc_func_dict, CMD_SNO, cmd_dummy);
+    dict_insert(irc_func_dict, TOK_SNO, cmd_dummy);
 
     dict_insert(irc_func_dict, CMD_RPING, cmd_rping);
     dict_insert(irc_func_dict, TOK_RPING, cmd_rping);
@@ -2558,6 +2534,7 @@ init_parse(void)
     /* ignore /trace and /motd commands targetted at us */
     dict_insert(irc_func_dict, TOK_TRACE, cmd_dummy);
     dict_insert(irc_func_dict, TOK_MOTD, cmd_dummy);
+    dict_insert(irc_func_dict, TOK_UPING, cmd_dummy);
 
     /* handle topics */
     dict_insert(irc_func_dict, "331", cmd_num_topic);
@@ -2802,15 +2779,13 @@ void DelServer(struct server* serv, int announce, const char *message)
 }
 
 struct userNode *
-AddLocalUser(const char *nick, const char *ident, const char *hostname, const char *desc, const char *modes)
+AddService(const char *nick, const char *modes, const char *desc, const char *hostname)
 {
     char numeric[COMBO_NUMERIC_LEN+1];
     int local_num = get_local_numeric();
     time_t timestamp = now;
     struct userNode *old_user = GetUserH(nick);
 
-    if (!modes)
-        modes = "+oik";
     if (old_user) {
         if (IsLocal(old_user))
             return old_user;
@@ -2823,7 +2798,8 @@ AddLocalUser(const char *nick, const char *ident, const char *hostname, const ch
     if (!hostname)
         hostname = self->name;
     make_numeric(self, local_num, numeric);
-    return AddUser(self, nick, ident, hostname, modes, numeric, desc, now, "AAAAAA");
+    /* TODO: Make these modes part of the conf file */
+    return AddUser(self, nick, nick, hostname, modes ? modes : "+oik", numeric, desc, now, "AAAAAA");
 }
 
 struct userNode *
@@ -2866,7 +2842,9 @@ static struct userNode*
 AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *numeric, const char *userinfo, time_t timestamp, const char *realip)
 {
     struct userNode *oldUser, *uNode;
-    unsigned int n, ignore_user, dummy;
+    unsigned int n, ignore_user;
+    char *tstr;
+    int type;
 
     if ((strlen(numeric) < 3) || (strlen(numeric) > 5)) {
         log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): numeric %s wrong length!", uplink, nick, numeric);
@@ -2883,10 +2861,7 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char *
         return NULL;
     }
 
-    dummy = modes && modes[0] == '*';
-    if (dummy) {
-        ++modes;
-    } else if (!is_valid_nick(nick)) {
+    if (!is_valid_nick(nick)) {
         log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): invalid nickname detected.", uplink, nick);
         return NULL;
     }
@@ -2918,18 +2893,21 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char *
     safestrncpy(uNode->numeric, numeric, sizeof(uNode->numeric));
     irc_p10_pton(&uNode->ip, realip);
 
-    if (irc_in_addr_is_ipv4(uNode->ip)) {
-      make_virtip((char*)irc_ntoa(&uNode->ip), (char*)irc_ntoa(&uNode->ip), uNode->cryptip);
-      make_virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost);
-    } else if (irc_in_addr_is_ipv6(uNode->ip)) {
-      make_ipv6virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost);
+    tstr = conf_get_data("server/type", RECDB_QSTRING);
+    type = atoi(tstr);
+    if (type > 6) {
+      if (irc_in_addr_is_ipv4(uNode->ip)) {
+        make_virtip((char*)irc_ntoa(&uNode->ip), (char*)irc_ntoa(&uNode->ip), uNode->cryptip);
+        make_virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost);
+      } else if (irc_in_addr_is_ipv6(uNode->ip)) {
+        make_ipv6virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost);
+      }
     }
 
     if (!uNode->crypthost && uNode->cryptip)
         snprintf(uNode->crypthost, sizeof(uNode->crypthost), "%s", strdup(uNode->cryptip));
 
     uNode->timestamp = timestamp;
-    uNode->idle_since = timestamp;
     modeList_init(&uNode->channels);
     uNode->uplink = uplink;
     if (++uNode->uplink->clients > uNode->uplink->max_clients) {
@@ -2938,8 +2916,6 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char *
     uNode->num_local = base64toint(numeric+strlen(uNode->uplink->numeric), 3) & uNode->uplink->num_mask;
     uNode->uplink->users[uNode->num_local] = uNode;
     mod_usermode(uNode, modes);
-    if (dummy)
-        uNode->modes |= FLAGS_DUMMY;
 
     set_geoip_info(uNode);
 
@@ -2979,7 +2955,7 @@ DelUser(struct userNode* user, struct userNode *killer, int announce, const char
 
     /* remove user from all channels */
     while (user->channels.used > 0)
-        DelChannelUser(user, user->channels.list[user->channels.used-1]->channel, NULL, false);
+        DelChannelUser(user, user->channels.list[user->channels.used-1]->channel, false, 0);
 
     /* Call these in reverse order so ChanServ can update presence
        information before NickServ nukes the handle_info. */
@@ -3024,14 +3000,6 @@ DelUser(struct userNode* user, struct userNode *killer, int announce, const char
     if(user->region) free(user->region);
     if(user->postal_code) free(user->postal_code);
 
-    if (IsLocal(user)) {
-        unsigned int num = user->num_local;
-        if (num < num_privmsg_funcs)
-            privmsg_funcs[num] = NULL;
-        if (num < num_notice_funcs)
-            notice_funcs[num] = NULL;
-    }
-
     /* We don't free them, in case we try to privmsg them or something
      * (like when a stupid oper kills themself).  We just put them onto
      * a list of clients that get freed after processing each line.
@@ -3084,6 +3052,38 @@ void mod_usermode(struct userNode *user, const char *mode_change) {
        case 'd': do_user_mode(FLAGS_DEAF); break;
        case 'k': do_user_mode(FLAGS_SERVICE); break;
        case 'g': do_user_mode(FLAGS_GLOBAL); break;
+       case 'B': do_user_mode(FLAGS_BOT); break;
+       case 'n': do_user_mode(FLAGS_HIDECHANS); break;
+       case 'I': do_user_mode(FLAGS_HIDEIDLE); break;
+       case 'X': do_user_mode(FLAGS_XTRAOP); break;
+       case 'C': do_user_mode(FLAGS_CLOAKHOST);
+           if (*word) {
+               char cloakhost[MAXLEN];
+               unsigned int ii;
+               for (ii=0; (*word != ' ') && (*word != '\0'); )
+                   cloakhost[ii++] = *word++;
+               cloakhost[ii] = 0;
+               while (*word == ' ')
+                   word++;
+               safestrncpy(user->crypthost, cloakhost, sizeof(user->crypthost));
+           }
+           break;
+       case 'c': do_user_mode(FLAGS_CLOAKIP);
+           if (*word) {
+               char cloakip[MAXLEN];
+               unsigned int ii;
+               for (ii=0; (*word != ' ') && (*word != '\0'); )
+                   cloakip[ii++] = *word++;
+               cloakip[ii] = 0;
+               while (*word == ' ')
+                   word++;
+               safestrncpy(user->cryptip, cloakip, sizeof(user->cryptip));
+           }
+           break;
+       // sethost - reed/apples
+       // case 'h': do_user_mode(FLAGS_HELPER); break;
+       // I check if there's an 'h' in the first part, and if there, 
+       // then everything after the space becomes their new host.
        case 'h': do_user_mode(FLAGS_SETHOST);
            if (*word) {
                char sethost[MAXLEN];
@@ -3096,8 +3096,6 @@ void mod_usermode(struct userNode *user, const char *mode_change) {
                safestrncpy(user->sethost, sethost, sizeof(user->sethost));
            }
            break;
-        case 'n': do_user_mode(FLAGS_NOCHAN); break;
-        case 'I': do_user_mode(FLAGS_NOIDLE); break;
         case 'x': do_user_mode(FLAGS_HIDDEN_HOST); break;
         case 'r':
             if (*word) {
@@ -3408,7 +3406,7 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod
             mod_chanmode_append(&chbuf, 'k', channel->key);
         if (change->modes_clear & channel->modes & MODE_UPASS)
             mod_chanmode_append(&chbuf, 'U', channel->upass);
-        if (change->modes_clear & channel->modes & MODE_APASS)
+        if (change->modes_clear * channel->modes & MODE_APASS)
             mod_chanmode_append(&chbuf, 'A', channel->apass);
     }
     for (arg = 0; arg < change->argc; ++arg) {
@@ -3705,10 +3703,9 @@ reg_privmsg_func(struct userNode *user, privmsg_func_t handler)
 {
     unsigned int numeric = user->num_local;
     if (numeric >= num_privmsg_funcs) {
-        int newnum = numeric + 8, ii;
+        int newnum = numeric + 8;
         privmsg_funcs = realloc(privmsg_funcs, newnum*sizeof(privmsg_func_t));
-        for (ii = num_privmsg_funcs; ii < newnum; ++ii)
-            privmsg_funcs[ii] = NULL;
+        memset(privmsg_funcs+num_privmsg_funcs, 0, (newnum-num_privmsg_funcs)*sizeof(privmsg_func_t));
         num_privmsg_funcs = newnum;
     }
     if (privmsg_funcs[numeric])
@@ -3717,12 +3714,20 @@ reg_privmsg_func(struct userNode *user, privmsg_func_t handler)
 }
 
 void
-unreg_privmsg_func(struct userNode *user)
+unreg_privmsg_func(struct userNode *user, privmsg_func_t handler)
 {
-    if (!IsLocal(user) || user->num_local >= num_privmsg_funcs)
+    unsigned int x;
+
+    if (!user || handler)
       return; /* this really only works with users */
 
-    privmsg_funcs[user->num_local] = NULL;
+    memset(privmsg_funcs+user->num_local, 0, sizeof(privmsg_func_t));
+
+    for (x = user->num_local+1; x < num_privmsg_funcs; x++) 
+       memmove(privmsg_funcs+x-1, privmsg_funcs+x, sizeof(privmsg_func_t));
+    
+    privmsg_funcs = realloc(privmsg_funcs, num_privmsg_funcs*sizeof(privmsg_func_t)); 
+    num_privmsg_funcs--;
 }
 
 
@@ -3731,10 +3736,9 @@ reg_notice_func(struct userNode *user, privmsg_func_t handler)
 {
     unsigned int numeric = user->num_local;
     if (numeric >= num_notice_funcs) {
-        int newnum = numeric + 8, ii;
+        int newnum = numeric + 8;
         notice_funcs = realloc(notice_funcs, newnum*sizeof(privmsg_func_t));
-        for (ii = num_privmsg_funcs; ii < newnum; ++ii)
-            privmsg_funcs[ii] = NULL;
+        memset(notice_funcs+num_notice_funcs, 0, (newnum-num_notice_funcs)*sizeof(privmsg_func_t));
         num_notice_funcs = newnum;
     }
     if (notice_funcs[numeric])
@@ -3743,12 +3747,21 @@ reg_notice_func(struct userNode *user, privmsg_func_t handler)
 }
 
 void
-unreg_notice_func(struct userNode *user)
+unreg_notice_func(struct userNode *user, privmsg_func_t handler)
 {
-    if (!IsLocal(user) || user->num_local >= num_privmsg_funcs)
+    unsigned int x;
+
+    if (!user || handler)
           return; /* this really only works with users */
 
-    notice_funcs[user->num_local] = NULL;
+    memset(notice_funcs+user->num_local, 0, sizeof(privmsg_func_t));
+
+    for (x = user->num_local+1; x < num_notice_funcs; x++)
+       memmove(notice_funcs+x-1, notice_funcs+x, sizeof(privmsg_func_t));
+
+    memset(notice_funcs+user->num_local, 0, sizeof(privmsg_func_t));
+    notice_funcs = realloc(notice_funcs, num_notice_funcs*sizeof(privmsg_func_t));
+    num_notice_funcs--;
 }
 
 void