Fix several bugs; make off-channel a per-channel option
authorMichael Poole <mdpoole@troilus.org>
Sun, 9 May 2004 03:05:48 +0000 (03:05 +0000)
committerMichael Poole <mdpoole@troilus.org>
Sun, 9 May 2004 03:05:48 +0000 (03:05 +0000)
* Add per-channel option (!set offchannel) for off-channel services
support.

* Rename REGISTERED_MODE to MODE_REGISTERED and always use it.

* Delete remaining (registered) channels on exit.

* Fix tests in proto-p10.c for chanop-ness when using off-channel
services support.
git-archimport-id: srvx@srvx.net--2004-srvx/srvx--devo--1.3--patch-60

ChangeLog
src/chanserv.c
src/chanserv.h
src/hash.c
src/hash.h
src/nickserv.c
src/proto-bahamut.c
src/proto-common.c
src/proto-p10.c
src/proto.h
srvx.conf.example

index 1642f8f8f0bbc43a3e5a6d5fcc7408ef6226dbdc..a1884665789cd6c2b8e452a65e3942552bf5c0f8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,29 @@
 # arch-tag: automatic-ChangeLog--srvx@srvx.net--2004-srvx/srvx--devo--1.3
 #
 
+2004-05-09 03:05:48 GMT        Michael Poole <mdpoole@troilus.org>     patch-60
+
+    Summary:
+      Fix several bugs; make off-channel a per-channel option
+    Revision:
+      srvx--devo--1.3--patch-60
+
+    * Add per-channel option (!set offchannel) for off-channel services
+    support.
+    
+    * Rename REGISTERED_MODE to MODE_REGISTERED and always use it.
+    
+    * Delete remaining (registered) channels on exit.
+    
+    * Fix tests in proto-p10.c for chanop-ness when using off-channel
+    services support.
+
+    modified files:
+     ChangeLog src/chanserv.c src/chanserv.h src/hash.c src/hash.h
+     src/nickserv.c src/proto-bahamut.c src/proto-common.c
+     src/proto-p10.c src/proto.h srvx.conf.example
+
+
 2004-05-07 14:32:06 GMT        Michael Poole <mdpoole@troilus.org>     patch-59
 
     Summary:
index 927522e50554757f6436c2e7341a25aabcb9dddc..dea2ad2818c66997accd9223ea64a87995aa57a4 100644 (file)
 #define KEY_EXPIRES             "expires"
 #define KEY_TRIGGERED          "triggered"
 
-#define CHANNEL_DEFAULT_FLAGS   (0)
+#define CHANNEL_DEFAULT_FLAGS   (CHANNEL_OFFCHANNEL)
 #define CHANNEL_DEFAULT_OPTIONS "lmoooanpcnat"
 
 /* Administrative messages */
@@ -252,6 +252,7 @@ static const struct message_entry msgtab[] = {
     { "CSMSG_SET_MODES",         "$bModes       $b %s" },
     { "CSMSG_SET_NODELETE",      "$bNoDelete    $b %s" },
     { "CSMSG_SET_DYNLIMIT",      "$bDynLimit    $b %s" },
+    { "CSMSG_SET_OFFCHANNEL",    "$bOffChannel  $b %s" },
     { "CSMSG_SET_USERINFO",      "$bUserInfo    $b %d" },
     { "CSMSG_SET_GIVE_VOICE",    "$bGiveVoice   $b %d" },
     { "CSMSG_SET_TOPICSNARF",    "$bTopicSnarf  $b %d" },
@@ -471,6 +472,7 @@ static int eject_user(struct userNode *user, struct chanNode *channel, unsigned
 
 struct userNode *chanserv;
 dict_t note_types;
+int off_channel;
 static dict_t plain_dnrs, mask_dnrs, handle_dnrs;
 static struct log_type *CS_LOG;
 
@@ -1268,6 +1270,7 @@ static void chanserv_expire_suspension(void *data);
 static void
 unregister_channel(struct chanData *channel, const char *reason)
 {
+    struct mod_chanmode change;
     char msgbuf[MAXLEN];
 
     /* After channel unregistration, the following must be cleaned
@@ -1284,22 +1287,29 @@ unregister_channel(struct chanData *channel, const char *reason)
 
     timeq_del(0, NULL, channel, TIMEQ_IGNORE_FUNC | TIMEQ_IGNORE_WHEN);
 
+    mod_chanmode_init(&change);
+    change.modes_clear |= MODE_REGISTERED;
+    mod_chanmode_announce(chanserv, channel->channel, &change);
+
     while(channel->users)
        del_channel_user(channel->users, 0);
 
     while(channel->bans)
        del_channel_ban(channel->bans);
 
-    if(channel->topic) free(channel->topic);
-    if(channel->registrar) free(channel->registrar);
-    if(channel->greeting) free(channel->greeting);
-    if(channel->user_greeting) free(channel->user_greeting);
-    if(channel->topic_mask) free(channel->topic_mask);
+    free(channel->topic);
+    free(channel->registrar);
+    free(channel->greeting);
+    free(channel->user_greeting);
+    free(channel->topic_mask);
 
-    if(channel->prev) channel->prev->next = channel->next;
-    else channelList = channel->next;
+    if(channel->prev)
+        channel->prev->next = channel->next;
+    else
+        channelList = channel->next;
 
-    if(channel->next) channel->next->prev = channel->prev;
+    if(channel->next)
+        channel->next->prev = channel->prev;
 
     if(channel->suspended)
     {
@@ -1321,8 +1331,7 @@ unregister_channel(struct chanData *channel, const char *reason)
     }
     channel->channel->channel_info = NULL;
 
-    if(channel->notes)
-        dict_delete(channel->notes);
+    dict_delete(channel->notes);
     sprintf(msgbuf, "%s %s", channel->channel->name, reason);
     if(!IsSuspended(channel))
         DelChannelUser(chanserv, channel->channel, msgbuf, 0);
@@ -4925,6 +4934,54 @@ static MODCMD_FUNC(chan_opt_dynlimit)
     CHANNEL_BINARY_OPTION("CSMSG_SET_DYNLIMIT", CHANNEL_DYNAMIC_LIMIT);
 }
 
+static MODCMD_FUNC(chan_opt_offchannel)
+{
+    struct chanData *cData = channel->channel_info;
+    int value;
+
+    if(argc > 1)
+    {
+       /* Set flag according to value. */
+       if(enabled_string(argv[1]))
+       {
+            if(!IsOffChannel(cData))
+                DelChannelUser(chanserv, channel, "Going off-channel.", 0);
+           cData->flags |= CHANNEL_OFFCHANNEL;
+           value = 1;
+       }
+       else if(disabled_string(argv[1]))
+       {
+            if(IsOffChannel(cData))
+            {
+                struct mod_chanmode change;
+                mod_chanmode_init(&change);
+                change.argc = 1;
+                change.args[0].mode = MODE_CHANOP;
+                change.args[0].member = AddChannelUser(chanserv, channel);
+                mod_chanmode_announce(chanserv, channel, &change);
+            }
+           cData->flags &= ~CHANNEL_OFFCHANNEL;
+           value = 0;
+       }
+       else
+       {
+           reply("MSG_INVALID_BINARY", argv[1]);
+           return 0;
+       }
+    }
+    else
+    {
+       /* Find current option value. */
+       value = (cData->flags & CHANNEL_OFFCHANNEL) ? 1 : 0;
+    }
+
+    if(value)
+        reply("CSMSG_SET_OFFCHANNEL", user_find_message(user, "MSG_ON"));
+    else
+        reply("CSMSG_SET_OFFCHANNEL", user_find_message(user, "MSG_OFF"));
+    return 1;
+}
+
 static MODCMD_FUNC(chan_opt_defaults)
 {
     struct userData *uData;
@@ -5915,7 +5972,7 @@ handle_auth(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle))
                && IsUserAutoInvite(channel)
                && (channel->access >= channel->channel->lvlOpts[lvlInviteMe])
                && !self->burst
-              && !user->uplink->burst)
+               && !user->uplink->burst)
                 irc_invite(chanserv, user, cn);
             continue;
         }
@@ -6243,7 +6300,6 @@ chanserv_conf_read(void)
     struct string_list *strlist;
     struct chanNode *chan;
     unsigned int ii;
-    extern int off_channel;
 
     if(!(conf_node = conf_get_data(CHANSERV_CONF_NAME, RECDB_OBJECT)))
     {
@@ -6540,7 +6596,6 @@ chanserv_channel_read(const char *key, struct record_data *hir)
     char *str, *argv[10];
     dict_iterator_t it;
     unsigned int argc;
-    extern int off_channel;
 
     channel = hir->d.object;
 
@@ -6631,7 +6686,7 @@ chanserv_channel_read(const char *key, struct record_data *hir)
         /* We could use suspended->expires and suspended->revoked to
          * set the CHANNEL_SUSPENDED flag, but we don't. */
     }
-    else if(cData->flags & CHANNEL_SUSPENDED)
+    else if(IsSuspended(cData))
     {
         suspended = calloc(1, sizeof(*suspended));
         suspended->issued = 0;
@@ -6646,27 +6701,22 @@ chanserv_channel_read(const char *key, struct record_data *hir)
         suspended->cData = cData;
     }
     else
-        suspended = NULL;
+        suspended = NULL; /* to squelch a warning */
 
-    if((cData->flags & CHANNEL_SUSPENDED)
-       && suspended->expires
-       && (suspended->expires <= now))
-    {
-        cData->flags &= ~CHANNEL_SUSPENDED;
+    if(IsSuspended(cData)) {
+        if(suspended->expires > now)
+            timeq_add(suspended->expires, chanserv_expire_suspension, suspended);
+        else if(suspended->expires)
+            cData->flags &= ~CHANNEL_SUSPENDED;
     }
 
-    if (!off_channel) {
-      if (!(cData->flags & CHANNEL_SUSPENDED)) {
-       struct mod_chanmode change;
-       mod_chanmode_init(&change);
-       change.argc = 1;
-       change.args[0].mode = MODE_CHANOP;
-       change.args[0].member = AddChannelUser(chanserv, cNode);
-       mod_chanmode_announce(chanserv, cNode, &change);
-
-      } else if (suspended->expires > now) {
-       timeq_add(suspended->expires, chanserv_expire_suspension, suspended);
-      }
+    if((!off_channel || !IsOffChannel(cData)) && !IsSuspended(cData)) {
+        struct mod_chanmode change;
+        mod_chanmode_init(&change);
+        change.argc = 1;
+        change.args[0].mode = MODE_CHANOP;
+        change.args[0].member = AddChannelUser(chanserv, cNode);
+        mod_chanmode_announce(chanserv, cNode, &change);
     }
 
     str = database_get_data(channel, KEY_REGISTERED, RECDB_QSTRING);
@@ -6684,16 +6734,15 @@ chanserv_channel_read(const char *key, struct record_data *hir)
     str = database_get_data(channel, KEY_TOPIC, RECDB_QSTRING);
     cData->topic = str ? strdup(str) : NULL;
 
-    if((str = database_get_data(channel, KEY_MODES, RECDB_QSTRING))
+    if(!IsSuspended(cData)
+       && (str = database_get_data(channel, KEY_MODES, RECDB_QSTRING))
        && (argc = split_line(str, 0, ArrayLength(argv), argv))
        && (modes = mod_chanmode_parse(cNode, argv, argc, MCP_KEY_FREE))) {
         cData->modes = *modes;
-       if(off_channel && !(REGISTERED_MODE == 0))
-         cData->modes.modes_set |= REGISTERED_MODE;
+        cData->modes.modes_set |= MODE_REGISTERED;
         if(cData->modes.argc > 1)
             cData->modes.argc = 1;
-        if(!IsSuspended(cData))
-            mod_chanmode_announce(chanserv, cNode, &cData->modes);
+        mod_chanmode_announce(chanserv, cNode, &cData->modes);
         mod_chanmode_free(modes);
     }
 
@@ -7171,6 +7220,8 @@ init_chanserv(const char *nick)
     DEFINE_CHANNEL_OPTION(ctcpusers);
     DEFINE_CHANNEL_OPTION(ctcpreaction);
     DEFINE_CHANNEL_OPTION(inviteme);
+    if(off_channel)
+        DEFINE_CHANNEL_OPTION(offchannel);
     modcmd_register(chanserv_module, "set defaults", chan_opt_defaults, 1, 0, "access", "owner", NULL);
 
     /* Alias set topic to set defaulttopic for compatibility. */
index 844c5af36e0d4a906173f52284c2f7a305f44780..bd437a8ce22de492a500c2b9a96a074121e23e26 100644 (file)
@@ -64,12 +64,14 @@ enum charOption {
 #define CHANNEL_DYNAMIC_LIMIT  0x00000020 /* (1 << 5) */
 #define CHANNEL_TOPIC_SNARF    0x00000040 /* (1 << 6) - DEPRECATED */
 #define CHANNEL_PEON_INVITE     0x00000080 /* (1 << 7) - DEPRECATED */
+#define CHANNEL_OFFCHANNEL      0x00000100 /* (1 << 8) */
 /* Flags with values over 0x20000000 or (1 << 29) will not work
  * because chanData.flags is a 30-bit field.
  */
 
 #define IsProtected(x)         ((x)->flags & CHANNEL_NODELETE)
 #define IsSuspended(x)         ((x)->flags & CHANNEL_SUSPENDED)
+#define IsOffChannel(x)         ((x)->flags & CHANNEL_OFFCHANNEL)
 
 struct chanData
 {
index cbe43ceaa9c1dc5627ff2f176e1eaf624ce7eb00..edd745421fca6e7cbd9fd2bf56a074943c1d9a15 100644 (file)
@@ -532,9 +532,8 @@ DelChannelUser(struct userNode* user, struct chanNode* channel, const char *reas
     struct modeNode* mNode;
     unsigned int n;
 
-    if (reason) {
+    if (reason)
         irc_part(user, channel, reason);
-    }
 
     mNode = GetUserMode(channel, user);
 
@@ -552,7 +551,7 @@ DelChannelUser(struct userNode* user, struct chanNode* channel, const char *reas
     modeList_remove(&user->channels, mNode);
     free(mNode);
 
-    if (!deleting && !channel->members.used && !channel->locks)
+    if (!deleting && !channel->members.used && !channel->locks && !(channel->modes & MODE_REGISTERED))
         DelChannel(channel);
 }
 
@@ -708,7 +707,13 @@ DEFINE_LIST(serverList, struct server*)
 static void
 hash_cleanup(void)
 {
+    dict_iterator_t it, next;
+
     DelServer(self, 0, NULL);
+    for (it = dict_first(channels); it; it = next) {
+        next = iter_next(it);
+        DelChannel(iter_data(it));
+    }
     dict_delete(channels);
     dict_delete(clients);
     dict_delete(servers);
index 82eddaeae193dbf8f718ad693f2bb5cdd938bf11..6ab5a869d79d2f9c0b69d9d579ff1808ea1681cf 100644 (file)
 #define MODE_BAN               0x0200 /* +b BAN */
 #define MODE_LIMIT             0x0400 /* +l LIMIT */
 #define MODE_DELAYJOINS         0x0800 /* +D */
-#define MODE_REGONLY            0x1000 /* +r */
+#define MODE_REGONLY            0x1000 /* ircu +r, Bahamut +R */
 #define MODE_NOCOLORS           0x2000 /* +c */
 #define MODE_NOCTCPS            0x4000 /* +C */
+#define MODE_REGISTERED         0x8000 /* Bahamut +r */
 #define MODE_REMOVE             0x80000000
 
 #define FLAGS_OPER             0x0001 /* Operator +O */
@@ -74,9 +75,6 @@
 #define IsReggedNick(x)         ((x)->modes & FLAGS_REGNICK)
 #define IsLocal(x)              ((x)->uplink == self)
 
-/* Please set this and define the mode you wish to be set/maintained on registered channels. */
-#define REGISTERED_MODE 0 
-
 #define NICKLEN         30
 #define USERLEN         10
 #define HOSTLEN         63
index 241df1e22bd953eb9f05d529c28974d83233a97d..66705c8a903a3deaaf8ac531c1a417584dbaa54e 100644 (file)
@@ -674,9 +674,9 @@ smart_get_handle_info(struct userNode *service, struct userNode *user, const cha
         }
         if (IsLocal(target)) {
            if (IsService(target))
-              send_message(user, service, "NSMSG_USER_IS_SERVICE", target->nick);
+                send_message(user, service, "NSMSG_USER_IS_SERVICE", target->nick);
            else
-             send_message(user, service, "MSG_USER_AUTHENTICATE", target->nick);
+                send_message(user, service, "MSG_USER_AUTHENTICATE", target->nick);
             return 0;
         }
         if (!(hi = target->handle_info)) {
index d79f247e4f0917830eae7c08512fa63db8480544..d0828f1c0c2c86b72064750be33672a3a66f968f 100644 (file)
@@ -584,6 +584,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;
@@ -1207,6 +1240,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;
@@ -1345,6 +1379,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);
@@ -1379,6 +1414,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);
@@ -1430,8 +1466,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) {
@@ -1446,6 +1483,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:
index 44f92faa703ee3b2c4119077afee209afbca74b0..8f5f1b9a791fd0f5d43a2a3815f1c0d038fb825b 100644 (file)
@@ -39,7 +39,6 @@ FILE *replay_file;
 struct io_fd *socket_io_fd;
 int force_n2k;
 const char *hidden_host_suffix;
-int off_channel;
 
 static char replay_line[MAXLEN+80];
 static int ping_freq;
@@ -367,44 +366,6 @@ static CMD_FUNC(cmd_stats)
     return 1;
 }
 
-static CMD_FUNC(cmd_whois)
-{
-    struct userNode *from;
-    struct userNode *who;
-#ifdef WITH_PROTOCOL_P10
-    extern char *his_servername;
-    extern char *his_servercomment;
-#endif
-
-    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_version)
 {
     struct userNode *user;
index aacaa59979d356f373cd0d168b3a9e5a2e45b5ff..046030ade02dcef2ea8ef79e85cfdda6dee0713b 100644 (file)
@@ -286,12 +286,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*
@@ -681,7 +682,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 +752,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;
@@ -1384,8 +1417,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);
@@ -2137,7 +2168,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 */
index bb06785da84896bbffc7f440e2c9f92b888c9729..23f76e60531207d90364be169aeece5d34f929fa 100644 (file)
@@ -87,8 +87,6 @@ struct cManagerNode
 #ifdef WITH_PROTOCOL_P10
 struct server* GetServerN(const char *numeric);
 struct userNode* GetUserN(const char *numeric);
-extern char *his_servername;
-extern char *his_servercomment;
 #endif
 
 /* Basic protocol parsing support. */
index 0d730519dbca88633b2b8f20dfa01458fb5e6a99..b016ea0fd3812d446f80ae989422431aed70bc61 100644 (file)
         // (This is changed relative srvx-1.0.x, which would use default
         // unless you specified ".disabled".)
         "nick" "ChanServ";
-       // Should ChanServ join the channel? Please do not ask the srvx dev
-       // team for help configuring your ircd or a patch if you attempt to
-       // use this option on ircds that do not support having services off
-       // of the channel. Most people will leave this off; we cannot assist
-       // you in designing your network to make this option usefull to you.
-       "off_channel" "no";
+        // Does your ircd have off-channel services support?
+        // Bahamut does; ircu2.10.11 does not.
+        "off_channel" "no";
         // how long should a person be unseen before resending infoline?
         "info_delay" "120";
         // maximum greeting length