Add fake host support (assuming your ircd supports it)
[srvx.git] / src / proto-bahamut.c
index 95dbe03c8b13cec11f87853e15837c6fd6e3ae4e..84531b0859eeaeaac9f2cc5f3fd6ba1b779d27fe 100644 (file)
@@ -1,11 +1,12 @@
 /* proto-bahamut.c - IRC protocol output
  * Copyright 2000-2004 srvx Development Team
  *
- * This program is free software; you can redistribute it and/or modify
+ * This file is part of srvx.
+ *
+ * srvx is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.  Important limitations are
- * listed in the COPYING file that accompanies this software.
+ * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,7 +14,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, email srvx-maintainers@srvx.net.
+ * along with srvx; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
  */
 
 #include "proto-common.c"
@@ -169,7 +171,7 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char *
 }
 
 struct userNode *
-AddService(const char *nick, const char *desc) {
+AddService(const char *nick, const char *desc, const char *hostname) {
     time_t timestamp = now;
     struct userNode *old_user = GetUserH(nick);
     struct in_addr ipaddr = { INADDR_LOOPBACK };
@@ -178,7 +180,9 @@ AddService(const char *nick, const char *desc) {
             return old_user;
         timestamp = old_user->timestamp - 1;
     }
-    return AddUser(self, nick, nick, self->name, "+oikr", desc, timestamp, ipaddr, 0);
+    if (!hostname)
+        hostname = self->name;
+    return AddUser(self, nick, nick, hostname, "+oikr", desc, timestamp, ipaddr, 0);
 }
 
 struct userNode *
@@ -267,6 +271,12 @@ irc_account(struct userNode *user, const char *stamp)
     }
 }
 
+void
+irc_fakehost(UNUSED_ARG(struct userNode *user), UNUSED_ARG(const char *host))
+{
+    /* not supported in bahamut */
+}
+
 void
 irc_regnick(struct userNode *user)
 {
@@ -305,11 +315,6 @@ irc_svinfo() {
     putsock("SVINFO 3 3 0 :"FMT_TIME_T, now);
 }
 
-void
-irc_burst() {
-    putsock("BURST");
-}
-
 void
 irc_introduce(const char *passwd) {
     extern time_t burst_begin;
@@ -367,6 +372,11 @@ irc_notice(struct userNode *from, const char *to, const char *message) {
     putsock(":%s NOTICE %s :%s", from->nick, to, message);
 }
 
+void
+irc_notice_user(struct userNode *from, struct userNode *to, const char *message) {
+    putsock(":%s NOTICE %s :%s", from->nick, to->nick, message);
+}
+
 void
 irc_wallchops(UNUSED_ARG(struct userNode *from), UNUSED_ARG(const char *to), UNUSED_ARG(const char *message)) {
 }
@@ -580,6 +590,39 @@ static CMD_FUNC(cmd_privmsg) {
     return 1;
 }
 
+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);
+#ifdef WITH_PROTOCOL_P10
+    if (his_servername && his_servercomment)
+      irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, his_servername, his_servercomment);
+    else
+#endif
+    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_capab) {
     static const struct {
         const char *name;
@@ -693,7 +736,6 @@ static CMD_FUNC(cmd_server) {
         AddServer(GetServerH(origin), argv[1], atoi(argv[2]), 0, now, 0, argv[3]);
     } else {
         self->uplink = AddServer(self, argv[1], atoi(argv[2]), 0, now, 0, argv[3]);
-        send_burst();
     }
     return 1;
 }
@@ -702,6 +744,7 @@ static CMD_FUNC(cmd_svinfo) {
     if (argc < 5) return 0;
     if ((atoi(argv[1]) < 3) || (atoi(argv[2]) > 3)) return 0;
     /* TODO: something with the timestamp we get from the other guy */
+    send_burst();
     return 1;
 }
 
@@ -1203,6 +1246,7 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un
             break;
 #define do_chan_mode(FLAG) do { if (add) change->modes_set |= FLAG, change->modes_clear &= ~FLAG; else change->modes_clear |= FLAG, change->modes_set &= ~FLAG; } while(0)
         case 'R': do_chan_mode(MODE_REGONLY); break;
+        case 'r': do_chan_mode(MODE_REGISTERED); break;
         case 'D': do_chan_mode(MODE_DELAYJOINS); break;
         case 'c': do_chan_mode(MODE_NOCOLORS); break;
         case 'i': do_chan_mode(MODE_INVITEONLY); break;
@@ -1258,13 +1302,19 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un
             if (!add)
                 change->args[ch_arg].mode |= MODE_REMOVE;
             victim = GetUserH(modes[in_arg++]);
+            if (!victim)
+                continue;
             if ((change->args[ch_arg].member = GetUserMode(channel, victim)))
                 ch_arg++;
             break;
         }
+        default:
+            if (!(flags & MCP_FROM_SERVER))
+                goto error;
+            break;
         }
     }
-    change->argc = argc; /* in case any turned out to be ignored */
+    change->argc = ch_arg; /* in case any turned out to be ignored */
     if (change->modes_set & MODE_SECRET) {
         change->modes_set &= ~(MODE_PRIVATE);
         change->modes_clear |= MODE_PRIVATE;
@@ -1314,6 +1364,7 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod
     char int_buff[32];
     unsigned int arg;
 
+    assert(change->argc <= change->alloc_argc);
     memset(&chbuf, 0, sizeof(chbuf));
     chbuf.channel = channel;
     chbuf.actor = who;
@@ -1334,6 +1385,7 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod
         DO_MODE_CHAR(DELAYJOINS, 'D');
         DO_MODE_CHAR(REGONLY, 'R');
         DO_MODE_CHAR(NOCOLORS, 'c');
+        DO_MODE_CHAR(REGISTERED, 'r');
 #undef DO_MODE_CHAR
         if (change->modes_clear & channel->modes & MODE_KEY)
             mod_chanmode_append(&chbuf, 'k', channel->key);
@@ -1368,6 +1420,7 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod
         DO_MODE_CHAR(DELAYJOINS, 'D');
         DO_MODE_CHAR(REGONLY, 'R');
         DO_MODE_CHAR(NOCOLORS, 'c');
+        DO_MODE_CHAR(REGISTERED, 'r');
 #undef DO_MODE_CHAR
         if (change->modes_set & MODE_KEY)
             mod_chanmode_append(&chbuf, 'k', change->new_key);
@@ -1406,6 +1459,7 @@ char *
 mod_chanmode_format(struct mod_chanmode *change, char *outbuff)
 {
     unsigned int used = 0;
+    assert(change->argc <= change->alloc_argc);
     if (change->modes_clear) {
         outbuff[used++] = '-';
 #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_clear & MODE_##BIT) outbuff[used++] = CHAR
@@ -1418,8 +1472,9 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff)
         DO_MODE_CHAR(LIMIT, 'l');
         DO_MODE_CHAR(KEY, 'k');
         DO_MODE_CHAR(DELAYJOINS, 'D');
-        DO_MODE_CHAR(REGONLY, '$');
+        DO_MODE_CHAR(REGONLY, 'R');
         DO_MODE_CHAR(NOCOLORS, 'c');
+        DO_MODE_CHAR(REGISTERED, 'r');
 #undef DO_MODE_CHAR
     }
     if (change->modes_set) {
@@ -1434,6 +1489,7 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff)
         DO_MODE_CHAR(DELAYJOINS, 'D');
         DO_MODE_CHAR(REGONLY, 'R');
         DO_MODE_CHAR(NOCOLORS, 'c');
+        DO_MODE_CHAR(REGISTERED, 'r');
 #undef DO_MODE_CHAR
         switch (change->modes_set & (MODE_KEY|MODE_LIMIT)) {
         case MODE_KEY|MODE_LIMIT: