Fix bugs; better handle oplevels from ircu2.10.12
[srvx.git] / src / proto-p10.c
index aacaa59979d356f373cd0d168b3a9e5a2e45b5ff..37eb33445040081cdd174fd3bed899005419d21a 100644 (file)
@@ -39,6 +39,7 @@
 #define CMD_EOB                 "END_OF_BURST"
 #define CMD_EOB_ACK             "EOB_ACK"
 #define CMD_ERROR               "ERROR"
+#define CMD_FAKEHOST            "FAKE"
 #define CMD_GET                        "GET"
 #define CMD_GLINE               "GLINE"
 #define CMD_HASH                "HASH"
 #define TOK_EOB                 "EB"
 #define TOK_EOB_ACK             "EA"
 #define TOK_ERROR               "Y"
+#define TOK_FAKEHOST            "FA"
 #define TOK_GET                        "GET"
 #define TOK_GLINE               "GL"
 #define TOK_HASH                "HASH"
 #define P10_EOB                 TYPE(EOB)
 #define P10_EOB_ACK             TYPE(EOB_ACK)
 #define P10_ERROR               TYPE(ERROR)
+#define P10_FAKEHOST            TYPE(FAKEHOST)
 #define P10_GET                        TYPE(GET)
 #define P10_GLINE               TYPE(GLINE)
 #define P10_HASH                TYPE(HASH)
@@ -286,12 +289,13 @@ static unsigned int num_privmsg_funcs;
 static privmsg_func_t *notice_funcs;
 static unsigned int num_notice_funcs;
 static struct dict *unbursted_channels;
-
-char *his_servername;
-char *his_servercomment;
+static char *his_servername;
+static char *his_servercomment;
 
 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);
 
+extern int off_channel;
+
 /* Numerics can be XYY, XYYY, or XXYYY; with X's identifying the
  * server and Y's indentifying the client on that server. */
 struct server*
@@ -417,6 +421,12 @@ irc_account(struct userNode *user, const char *stamp)
     putsock("%s " P10_ACCOUNT " %s %s", self->numeric, user->numeric, stamp);
 }
 
+void
+irc_fakehost(struct userNode *user, const char *host)
+{
+    putsock("%s " P10_FAKEHOST " %s %s", self->numeric, user->numeric, host);
+}
+
 void
 irc_regnick(UNUSED_ARG(struct userNode *user))
 {
@@ -681,7 +691,7 @@ irc_kick(struct userNode *who, struct userNode *target, struct chanNode *channel
 {
     const char *numeric;
     struct modeNode *mn = GetUserMode(channel, who);
-    numeric = ((!mn && off_channel) || (mn->modes & MODE_CHANOP)) ? who->numeric : self->numeric;
+    numeric = ((mn && (mn->modes & MODE_CHANOP)) || off_channel) ? who->numeric : self->numeric;
     putsock("%s " P10_KICK " %s %s :%s",
             numeric, channel->name, target->numeric, msg);
 }
@@ -751,6 +761,36 @@ change_nicklen(int new_nicklen)
     }
 }
 
+static CMD_FUNC(cmd_whois)
+{
+    struct userNode *from;
+    struct userNode *who;
+
+    if (argc < 3)
+        return 0;
+    if (!(from = GetUserH(origin))) {
+        log_module(MAIN_LOG, LOG_ERROR, "Could not find WHOIS origin user %s", origin);
+        return 0;
+    }
+    if(!(who = GetUserH(argv[2]))) {
+        irc_numeric(from, ERR_NOSUCHNICK, "%s@%s :No such nick", argv[2], self->name);
+        return 1;
+    }
+    if (IsHiddenHost(who) && !IsOper(from)) {
+        /* Just stay quiet. */
+        return 1;
+    }
+    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 (IsOper(who))
+        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;
+}
+
 static CMD_FUNC(cmd_server)
 {
     struct server *srv;
@@ -758,7 +798,7 @@ static CMD_FUNC(cmd_server)
 
     if (argc < 8)
         return 0;
-    if (origin) {
+    if (self->uplink) {
         /* another server introduced us */
         srv = AddServer(GetServerH(origin), argv[1], atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), argv[6], argv[argc-1]);
         if (!srv)
@@ -973,6 +1013,18 @@ static CMD_FUNC(cmd_account)
     return 1;
 }
 
+static CMD_FUNC(cmd_fakehost)
+{
+    struct userNode *user;
+
+    if ((argc < 3) || !origin || !GetServerH(origin))
+        return 0;
+    if (!(user = GetUserN(argv[1])))
+        return 1;
+    assign_fakehost(user, argv[2], 0);
+    return 1;
+}
+
 static CMD_FUNC(cmd_burst)
 {
     extern int rel_age;
@@ -1024,7 +1076,10 @@ static CMD_FUNC(cmd_burst)
                     mode |= MODE_CHANOP;
                 else if (sep == 'v')
                     mode |= MODE_VOICE;
-                else
+                else if (isdigit(sep)) {
+                    mode |= MODE_CHANOP;
+                    while (isdigit(*end)) end++;
+                } else
                     break;
             }
             if (rel_age < 0)
@@ -1151,7 +1206,7 @@ static CMD_FUNC(cmd_topic)
 
 static CMD_FUNC(cmd_num_topic)
 {
-    static struct chanNode *cn;
+    struct chanNode *cn;
 
     if (!argv[0])
         return 0; /* huh? */
@@ -1384,8 +1439,6 @@ init_parse(void)
     const char *str, *desc;
     int numnick, usermask, max_users;
     char numer[COMBO_NUMERIC_LEN+1];
-    extern char *his_servername;
-    extern char *his_servercomment;
 
     /* read config items */
     str = conf_get_data("server/ping_freq", RECDB_QSTRING);
@@ -1438,6 +1491,8 @@ init_parse(void)
     dict_insert(irc_func_dict, TOK_NICK, cmd_nick);
     dict_insert(irc_func_dict, CMD_ACCOUNT, cmd_account);
     dict_insert(irc_func_dict, TOK_ACCOUNT, cmd_account);
+    dict_insert(irc_func_dict, CMD_FAKEHOST, cmd_fakehost);
+    dict_insert(irc_func_dict, TOK_FAKEHOST, cmd_fakehost);
     dict_insert(irc_func_dict, CMD_PASS, cmd_pass);
     dict_insert(irc_func_dict, TOK_PASS, cmd_pass);
     dict_insert(irc_func_dict, CMD_PING, cmd_ping);
@@ -1514,6 +1569,7 @@ init_parse(void)
     dict_insert(irc_func_dict, "331", cmd_num_topic);
     dict_insert(irc_func_dict, "332", cmd_num_topic);
     dict_insert(irc_func_dict, "333", cmd_num_topic);
+    dict_insert(irc_func_dict, "345", cmd_dummy); /* blah has been invited to blah */
     dict_insert(irc_func_dict, "432", cmd_error_nick); /* Erroneus [sic] nickname */
     /* ban list resetting */
     /* "stats g" responses */
@@ -1746,7 +1802,7 @@ void DelServer(struct server* serv, int announce, const char *message)
 }
 
 struct userNode *
-AddService(const char *nick, const char *desc, const char *hostname)
+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();
@@ -1765,7 +1821,7 @@ AddService(const char *nick, const char *desc, const char *hostname)
     if (!hostname)
         hostname = self->name;
     make_numeric(self, local_num, numeric);
-    return AddUser(self, nick, nick, hostname, "+oik", numeric, desc, now, "AAAAAA");
+    return AddUser(self, nick, nick, hostname, modes ? modes : "+oik", numeric, desc, now, "AAAAAA");
 }
 
 struct userNode *
@@ -1934,8 +1990,8 @@ void mod_usermode(struct userNode *user, const char *mode_change) {
 
     if (!user || !mode_change)
         return;
-    while (*word != ' ' && *word) word++;\
-    while (*word == ' ') word++; \
+    while (*word != ' ' && *word) word++;
+    while (*word == ' ') word++;
     while (1) {
 #define do_user_mode(FLAG) do { if (add) user->modes |= FLAG; else user->modes &= ~FLAG; } while (0)
        switch (*mode_change++) {
@@ -1977,6 +2033,18 @@ void mod_usermode(struct userNode *user, const char *mode_change) {
                 call_account_func(user, tag);
             }
             break;
+        case 'f':
+            if (*word) {
+                char host[MAXLEN];
+                unsigned int ii;
+                for (ii=0; (*word != ' ') && (*word != '\0'); )
+                    host[ii++] = *word++;
+                host[ii] = 0;
+                while (*word == ' ')
+                    word++;
+                assign_fakehost(user, host, 0);
+            }
+            break;
        }
 #undef do_user_mode
     }
@@ -2049,7 +2117,7 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un
             change->args[ch_arg].mode = MODE_BAN;
             if (!add)
                 change->args[ch_arg].mode |= MODE_REMOVE;
-            change->args[ch_arg++].hostmask = modes[in_arg++];
+            change->args[ch_arg++].u.hostmask = modes[in_arg++];
             break;
         case 'o': case 'v':
         {
@@ -2067,7 +2135,7 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un
                 victim = GetUserH(modes[in_arg++]);
             if (!victim)
                 continue;
-            if ((change->args[ch_arg].member = GetUserMode(channel, victim)))
+            if ((change->args[ch_arg].u.member = GetUserMode(channel, victim)))
                 ch_arg++;
             break;
         }
@@ -2137,7 +2205,7 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod
     chbuf.chname_len = strlen(channel->name);
 
     mn = GetUserMode(channel, who);
-    if ((!mn && off_channel) || (mn->modes & MODE_CHANOP))
+    if ((mn && (mn->modes & MODE_CHANOP)) || off_channel)
         chbuf.is_chanop = 1;
 
     /* First remove modes */
@@ -2168,13 +2236,13 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod
             chbuf.modes[chbuf.modes_used++] = mode = '-';
         switch (change->args[arg].mode & ~MODE_REMOVE) {
         case MODE_BAN:
-            mod_chanmode_append(&chbuf, 'b', change->args[arg].hostmask);
+            mod_chanmode_append(&chbuf, 'b', change->args[arg].u.hostmask);
             break;
         default:
             if (change->args[arg].mode & MODE_CHANOP)
-                mod_chanmode_append(&chbuf, 'o', change->args[arg].member->user->numeric);
+                mod_chanmode_append(&chbuf, 'o', change->args[arg].u.member->user->numeric);
             if (change->args[arg].mode & MODE_VOICE)
-                mod_chanmode_append(&chbuf, 'v', change->args[arg].member->user->numeric);
+                mod_chanmode_append(&chbuf, 'v', change->args[arg].u.member->user->numeric);
             break;
         }
     }
@@ -2210,13 +2278,13 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod
             chbuf.modes[chbuf.modes_used++] = mode = '+';
         switch (change->args[arg].mode) {
         case MODE_BAN:
-            mod_chanmode_append(&chbuf, 'b', change->args[arg].hostmask);
+            mod_chanmode_append(&chbuf, 'b', change->args[arg].u.hostmask);
             break;
         default:
             if (change->args[arg].mode & MODE_CHANOP)
-                mod_chanmode_append(&chbuf, 'o', change->args[arg].member->user->numeric);
+                mod_chanmode_append(&chbuf, 'o', change->args[arg].u.member->user->numeric);
             if (change->args[arg].mode & MODE_VOICE)
-                mod_chanmode_append(&chbuf, 'v', change->args[arg].member->user->numeric);
+                mod_chanmode_append(&chbuf, 'v', change->args[arg].u.member->user->numeric);
             break;
         }
     }
@@ -2308,7 +2376,7 @@ clear_chanmode(struct chanNode *channel, const char *modes)
         case 'b': remove |= MODE_BAN; break;
         case 'D': remove |= MODE_DELAYJOINS; break;
         case 'r': remove |= MODE_REGONLY; break;
-        case 'c': remove |= MODE_NOCOLORS;
+        case 'c': remove |= MODE_NOCOLORS; break;
         case 'C': remove |= MODE_NOCTCPS; break;
         }
     }