Add fake host support (assuming your ircd supports it)
[srvx.git] / src / proto-p10.c
index 4340ff54136aad7dcedd40d9ea1948f24c8f4cfd..b2aa696fdd7e1ec0376db60ad64ffd906d9cfb1c 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))
 {
@@ -563,8 +573,6 @@ irc_burst(struct chanNode *chan)
     long last_mode=-1;
     unsigned int n;
 
-    if (!chan->members.used)
-        return;
     base_len = sprintf(burst_line, "%s " P10_BURST " %s " FMT_TIME_T " ",
                        self->numeric, chan->name, chan->timestamp);
     len = irc_make_chanmode(chan, burst_line+base_len);
@@ -683,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 && (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);
 }
@@ -753,6 +761,38 @@ 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;
@@ -975,6 +1015,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;
@@ -1153,7 +1205,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? */
@@ -1386,8 +1438,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);
@@ -1410,10 +1460,12 @@ init_parse(void)
         inttobase64(numer, (numnick << 12) + (usermask & 0x00fff), 3);
     else
         inttobase64(numer, (numnick << 18) + (usermask & 0x3ffff), 5);
+
     str = conf_get_data("server/his_servername", RECDB_QSTRING);
     his_servername = str ? strdup(str) : NULL;
     str = conf_get_data("server/his_servercomment", RECDB_QSTRING);
     his_servercomment = str ? strdup(str) : NULL;
+
     str = conf_get_data("server/hostname", RECDB_QSTRING);
     desc = conf_get_data("server/description", RECDB_QSTRING);
     if (!str || !desc) {
@@ -1438,6 +1490,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 +1568,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 */
@@ -1977,6 +2032,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
     }
@@ -2135,7 +2202,9 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod
     chbuf.channel = channel;
     chbuf.actor = who;
     chbuf.chname_len = strlen(channel->name);
-    if ((mn = GetUserMode(channel, who)) && (mn->modes & MODE_CHANOP))
+
+    mn = GetUserMode(channel, who);
+    if ((mn && (mn->modes & MODE_CHANOP)) || off_channel)
         chbuf.is_chanop = 1;
 
     /* First remove modes */