Author: Isomer <isomer@coders.net>
authorPerry Lorier <isomer@undernet.org>
Mon, 30 Oct 2000 09:28:15 +0000 (09:28 +0000)
committerPerry Lorier <isomer@undernet.org>
Mon, 30 Oct 2000 09:28:15 +0000 (09:28 +0000)
Log message:

Lots of little changes

To check:
 * glines
 * ./ircd --help doesn't start the server
 * silence works
 * check oper still owkrs
 * check error messages on accept
 * lotsa other things, read the changelog :)

git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@303 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

13 files changed:
ChangeLog
Makefile.in
config/configure
config/configure.in
doc/rfc1459.unet
ircd/class.c
ircd/listener.c
ircd/m_create.c
ircd/m_oper.c
ircd/m_server.c
ircd/m_stats.c
ircd/m_topic.c
ircd/s_err.c

index 94cc930efa95444e16c0e2e9033a6e518b43f2de..fa16d2687a7672e9b6679932b613bff6ae5ed175 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2000-10-30  Isomer <isomer@coders.net>
+
+       * ircd/m_topic.c: Restructured, fixed bug where topics on local
+       channels are propergated (I forget who pointed this out to me, but
+       thanks anyway).  Also to save bandwidth don't send the topic to
+       users if the topic is already the same on the server (but still
+       propergate to other servers).  X/W's "autotopic" feature must
+       chew a lot of bandwidth, hopefully this will help reduce this.
+
+       * doc/rfc1459.rfc: Updated documentation on /topic.
+
+       * ircd/listener.c: snotice warnings about failed accept()'s
+       potentially warning admins that they're running out of fd's.
+
+       * ircd/stats.c, ircd/class.c: Removed /stats v, added number of
+       people in a class in /stats y
+
+       * ircd/m_create.c: Checks for timewarp hacking and squit's
+       evil servers. (currently disabled)
+       
+
 2000-10-30  net <simms@lucida.qc.ca>
        
        * ircd/gline.c: Fixed various bugs Isomer left behind.
index 8a0bad9dd987e645688475ed1b195e7799f81f62..38ec813d543f9ec94b66f554e811e98a45cf22f7 100644 (file)
@@ -35,7 +35,7 @@ all: build
 
 build:
        @if [ ! -f config/config.h ]; then \
-               echo "Run 'make config' to configure the server"; \
+               $(MAKE) config; \
        else \
          for i in config ircd; do \
                  echo "Building $$i..."; \
index 7863a686f1438a5f5f959ed5ffc276ac08bc2655..fb17a271396c5cf18c72e0e382bbb6b91099a874 100644 (file)
@@ -2371,12 +2371,16 @@ EOF
 fi
 
 
+echo $ac_n "checking for donuts""... $ac_c" 1>&6
+echo "configure:2376: checking for donuts" >&5
+echo "$ac_t""yes" 1>&6
+
 for ac_prog in gawk mawk nawk awk
 do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:2380: checking for $ac_word" >&5
+echo "configure:2384: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2406,7 +2410,7 @@ test -n "$AWK" && break
 done
 
 echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
-echo "configure:2410: checking whether ${MAKE-make} sets \${MAKE}" >&5
+echo "configure:2414: checking whether ${MAKE-make} sets \${MAKE}" >&5
 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -2444,7 +2448,7 @@ fi
 # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
 # ./install, which can be erroneously created by make from ./install.sh.
 echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:2448: checking for a BSD compatible install" >&5
+echo "configure:2452: checking for a BSD compatible install" >&5
 if test -z "$INSTALL"; then
 if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -2497,7 +2501,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
 test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
 
 echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
-echo "configure:2501: checking whether ln -s works" >&5
+echo "configure:2505: checking whether ln -s works" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2522,7 +2526,7 @@ do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:2526: checking for $ac_word" >&5
+echo "configure:2530: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_RMPROG'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2563,7 +2567,7 @@ do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:2567: checking for $ac_word" >&5
+echo "configure:2571: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_SHPROG'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2601,7 +2605,7 @@ test -n "$SHPROG" || SHPROG="/bin/sh"
 
 
 echo $ac_n "checking for set -h""... $ac_c" 1>&6
-echo "configure:2605: checking for set -h" >&5
+echo "configure:2609: checking for set -h" >&5
 if eval "test \"`echo '$''{'unet_cv_sys_set_h'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2620,7 +2624,7 @@ echo "$ac_t""$unet_cv_sys_set_h" 1>&6
 
 
 echo $ac_n "checking for posix non-blocking""... $ac_c" 1>&6
-echo "configure:2624: checking for posix non-blocking" >&5
+echo "configure:2628: checking for posix non-blocking" >&5
 if eval "test \"`echo '$''{'unet_cv_sys_nonblocking_posix'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2628,7 +2632,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 2632 "configure"
+#line 2636 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -2654,7 +2658,7 @@ int main(void)
   exit(1);
 }
 EOF
-if { (eval echo configure:2658: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2662: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   unet_cv_sys_nonblocking_posix=yes
 else
@@ -2676,7 +2680,7 @@ EOF
 
 else
 echo $ac_n "checking for bsd non-blocking""... $ac_c" 1>&6
-echo "configure:2680: checking for bsd non-blocking" >&5
+echo "configure:2684: checking for bsd non-blocking" >&5
 if eval "test \"`echo '$''{'unet_cv_sys_nonblocking_bsd'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2684,7 +2688,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 2688 "configure"
+#line 2692 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -2710,7 +2714,7 @@ int main(void)
   exit(1);
 }
 EOF
-if { (eval echo configure:2714: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2718: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   unet_cv_sys_nonblocking_bsd=yes
 else
@@ -2738,19 +2742,19 @@ EOF
 fi
 fi
 echo $ac_n "checking for posix signals""... $ac_c" 1>&6
-echo "configure:2742: checking for posix signals" >&5
+echo "configure:2746: checking for posix signals" >&5
 if eval "test \"`echo '$''{'unet_cv_sys_signal_posix'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2747 "configure"
+#line 2751 "configure"
 #include "confdefs.h"
 #include <signal.h>
 int main() {
 sigaction(SIGTERM, (struct sigaction *)0L, (struct sigaction *)0L)
 ; return 0; }
 EOF
-if { (eval echo configure:2754: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2758: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   unet_cv_sys_signal_posix=yes
 else
@@ -2770,7 +2774,7 @@ EOF
 
 else
 echo $ac_n "checking for bsd reliable signals""... $ac_c" 1>&6
-echo "configure:2774: checking for bsd reliable signals" >&5
+echo "configure:2778: checking for bsd reliable signals" >&5
 if eval "test \"`echo '$''{'unet_cv_sys_signal_bsd'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2778,7 +2782,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 2782 "configure"
+#line 2786 "configure"
 #include "confdefs.h"
 #include <signal.h>
 int calls = 0;
@@ -2796,7 +2800,7 @@ int main(void)
   exit (0);
 }
 EOF
-if { (eval echo configure:2800: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2804: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   unet_cv_sys_signal_bsd=yes
 else
@@ -2825,20 +2829,20 @@ fi
 fi
 
 echo $ac_n "checking if the compiler understands -pipe""... $ac_c" 1>&6
-echo "configure:2829: checking if the compiler understands -pipe" >&5
+echo "configure:2833: checking if the compiler understands -pipe" >&5
 unet_cv_pipe_flags="$ac_cv_prog_gcc"
 if test "$ac_cv_prog_gcc" = no; then
   OLDCFLAGS="$CFLAGS"
   CFLAGS="$CFLAGS -pipe"
   cat > conftest.$ac_ext <<EOF
-#line 2835 "configure"
+#line 2839 "configure"
 #include "confdefs.h"
 
 int main() {
 
 ; return 0; }
 EOF
-if { (eval echo configure:2842: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2846: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   unet_cv_pipe_flags=yes
 else
@@ -2863,7 +2867,7 @@ fi
 
 uname=`uname`
 echo $ac_n "checking for OS type""... $ac_c" 1>&6
-echo "configure:2867: checking for OS type" >&5
+echo "configure:2871: checking for OS type" >&5
 case "$uname" in
   *inux*)
     echo "$ac_t""$uname found." 1>&6
index 5c2e776033b26709a8aac98631199d5e1a01bf31..52653e8e73de41d16835328d5fc94fce958894c1 100644 (file)
@@ -75,6 +75,10 @@ unet_FUNC_POLL_SYSCALL
 dnl Do we have restarting syscalls ?
 AC_SYS_RESTARTABLE_SYSCALLS
 
+dnl Check for required features for admins?
+AC_MSG_CHECKING([for donuts])
+AC_MSG_RESULT([yes])
+
 dnl Test for programs
 AC_PROG_AWK
 AC_PROG_MAKE_SET
index 4e04b29c22fa14adf4501b650f5186251ba35283..99794a6015cf5fcd74e8af60720c7526ed7e742a 100644 (file)
@@ -1285,12 +1285,16 @@ MODE WiZ -o                     ; WiZ 'deopping' (removing operator
    The topic for channel <channel> is returned if there is no <topic>
    given.  If the <topic> parameter is present, the topic for that
    channel will be changed, if the channel modes permit this action.
+   You may not query a topic from outside a secret channel.  Modeless
+   channels don't have a topic and thus ERR_CHANOPRIVSNEEDED is returned.
+   A list of channels may be specified comma seperated.
 
    Numeric Replies:
 
            ERR_NEEDMOREPARAMS              ERR_NOTONCHANNEL
            RPL_NOTOPIC                     RPL_TOPIC
-           ERR_CHANOPRIVSNEEDED
+           ERR_CHANOPRIVSNEEDED            ERR_NOSUCHCHANNEL
+          RPL_TOPICWHOTIME
 
 
 
@@ -1308,6 +1312,11 @@ RFC 1459              Internet Relay Chat Protocol              May 1993
 
    TOPIC #test                     ; check the topic for #test.
 
+   TOPIC #test,#testing            ; check the topic on #test and #testing
+
+   TOPIC #test,#testing :Topic     ; set the topic on #test and #testing
+0
+
 4.2.5 Names message
 
       Command: NAMES
index 77678e9d2fed5fdb62898bba1037199e183af3ec..2f302161b7965dda4bb1b0b5137c214af66fdd12 100644 (file)
@@ -253,7 +253,8 @@ void report_classes(struct Client *sptr)
 
   for (cltmp = connClassList; cltmp; cltmp = cltmp->next)
     send_reply(sptr, RPL_STATSYLINE, 'Y', ConClass(cltmp), PingFreq(cltmp),
-              ConFreq(cltmp), MaxLinks(cltmp), MaxSendq(cltmp));
+              ConFreq(cltmp), MaxLinks(cltmp), MaxSendq(cltmp),
+              Links(cltmp));
 }
 
 unsigned int get_sendq(struct Client *cptr)
index 0a0285db8b76f15cdf9c4aa8a9cf2cde75a90086..f6ce0e3df52abef023ecd28c20da99e9be30f2ff 100644 (file)
@@ -413,6 +413,12 @@ void accept_connection(struct Listener* listener)
    * be accepted until some old is closed first.
    */
   if (-1 == (fd = accept(listener->fd, (struct sockaddr*) &addr, &addrlen))) {
+    /* Lotsa admins seem to have problems with not giving enough file descriptors
+     * to their server so we'll add a generic warning mechanism here.  If it
+     * turns out too many messages are generated for meaningless reasons we
+     * can filter them back.
+     */
+    sendto_op_mask(SNO_TCPCOMMON,"Unable to accept connection: %s", strerror(errno));
     return;
   }
   /*
index c3d537bf9a6c8058c36d6b04440fc4901ace6a45..6333645ad15965a526aa03b45f25e188caea247d 100644 (file)
@@ -123,7 +123,7 @@ int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
   }
 
   /* sanity checks: Only accept CREATE messages from servers */
-  if (!IsServer(cptr) || parc < 3 || *parv[2] == '\0')
+  if (parc < 3 || *parv[2] == '\0')
     return 0;
 
   chanTS = atoi(parv[2]);
@@ -138,6 +138,18 @@ int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       MAGIC_REMOTE_JOIN_TS != chanTS)
     sptr->user->server->serv->lag = TStime() - chanTS;
 
+#if 0  
+  /* If this server is >5 minutes fast, squit it */
+  if (TStime() - chanTS<-5*60*60)
+       return exit_client(sptr,sptr,"Timestamp Drift/Bogus TS");
+       
+  /* If we recieve a CREATE for a channel from a server before that server
+   * was linked, then it's a HACK
+   */
+  if (MyConnect(sptr) && chanTS<sptr->timestamp+5*60*60)
+       return exit_client(sptr,sptr,"HACK: Bogus TS on CREATE before server link");
+#endif
+
   /* For each channel in the comma seperated list: */
   for (name = ircd_strtok(&p, parv[1], ","); name;
        name = ircd_strtok(&p, 0, ",")) {
index d51c00ff8bcc30a99bb246b029e640edd2e56ceb..60156db6bf66ad245c5edd2ca38dfbfdcae3fd9b 100644 (file)
@@ -118,12 +118,7 @@ int oper_password_match(const char* to_match, const char* passwd)
    * passwd may be NULL. Head it off at the pass...
    */
   if (to_match && passwd) {
-    char salt[3];
-    const char* encr;
-    salt[0] = passwd[0];
-    salt[1] = passwd[1];
-    salt[2] = '\0';
-    encr = ircd_crypt(to_match, salt);
+    encr = ircd_crypt(to_match, passwd);
     return (0 == strcmp(encr, passwd));
   }
   return 0;
index 2a63dcbe032ae26f91058ef355e37e25ab2fd7cd..b0af144cbd227808ed90f75bb60822e8d5603415 100644 (file)
@@ -337,12 +337,7 @@ int mr_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 #ifdef CRYPT_LINK_PASSWORD
     /* passwd may be NULL. Head it off at the pass... */
     if (*cptr->passwd) {
-      char salt[3];
-
-      salt[0] = aconf->passwd[0];
-      salt[1] = aconf->passwd[1];
-      salt[2] = '\0';
-      encr = ircd_crypt(cptr->passwd, salt);
+      encr = ircd_crypt(cptr->passwd, aconf->passed);
     }
     else
       encr = "";
@@ -1011,12 +1006,7 @@ int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     /* passwd may be NULL. Head it off at the pass... */
     if (*cptr->passwd)
     {
-      char salt[3];
-
-      salt[0] = aconf->passwd[0];
-      salt[1] = aconf->passwd[1];
-      salt[2] = '\0';
-      encr = ircd_crypt(cptr->passwd, salt);
+      encr = ircd_crypt(cptr->passwd, aconf->passwd);
     }
     else
       encr = "";
@@ -1672,12 +1662,7 @@ int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
     /* passwd may be NULL. Head it off at the pass... */
     if (*cptr->passwd)
     {
-      char salt[3];
-
-      salt[0] = aconf->passwd[0];
-      salt[1] = aconf->passwd[1];
-      salt[2] = '\0';
-      encr = ircd_crypt(cptr->passwd, salt);
+      encr = ircd_crypt(cptr->passwd, aconf->passwd);
     }
     else
       encr = "";
index 118d7460115a14a69adaff60c56cf1391960195b..abbf54cc735bc0cb7d1b50aa720abf3839123a95 100644 (file)
@@ -372,16 +372,6 @@ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       send_reply(sptr, RPL_STATSCONN, max_connection_count, max_client_count);
       break;
     }
-    case 'v':
-      {
-        const struct ConnectionClass* cl = get_class_list();
-
-        for ( ; cl; cl = cl->next) {
-          if (Links(cl) > 0)
-            send_reply(sptr, RPL_TRACECLASS, ConClass(cl), Links(cl));
-        }
-      }
-      break;
     case 'W':
     case 'w':
       calc_load(sptr);
@@ -618,17 +608,6 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       send_reply(sptr, RPL_STATSCONN, max_connection_count, max_client_count);
       break;
     }
-    case 'v':
-      {
-        const struct ConnectionClass* cl = get_class_list();
-            
-        for ( ; cl; cl = cl->next) {
-          if (Links(cl) > 0)
-            send_reply(sptr, RPL_TRACECLASS, ConClass(cl), Links(cl));
-        }
-      }
-      break;
-    
     case 'W':
     case 'w':
       calc_load(sptr);
@@ -854,16 +833,6 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       send_reply(sptr, RPL_STATSCONN, max_connection_count, max_client_count);
       break;
     }
-    case 'v':
-      {
-        const struct ConnectionClass* cl = get_class_list();
-            
-        for ( ; cl; cl = cl->next) {
-          if (Links(cl) > 0)
-            send_reply(sptr, RPL_TRACECLASS, ConClass(cl), Links(cl));
-        }
-      }
-      break;
     case 'W':
     case 'w':
       calc_load(sptr);
index 2d963d59fde98876fbbc85603efa8b5a0ae8db00..039c1a60589751bef90627c0560ede72dcf4b0f0 100644 (file)
 
 #include <assert.h>
 
-/*
- * m_topic - generic message handler
- *
- * parv[0]        = sender prefix
- * parv[1]        = channel
- * parv[parc - 1] = topic (if parc > 2)
- */
-int m_topic(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+static void do_settopic(struct Client *sptr, struct Client *cptr, 
+                       struct Channel *chptr,char *topic)
 {
-  struct Channel *chptr;
-  char *topic = 0, *name, *p = 0;
-
-  if (parc < 2)
-    return need_more_params(sptr, "TOPIC");
-
-  if (parc > 2)
-    topic = parv[parc - 1];
-
-  for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
-  {
-    chptr = 0;
-    if (!IsChannelName(name) || !(chptr = FindChannel(name)) ||
-        ((topic || SecretChannel(chptr)) && !find_channel_member(sptr, chptr)))
-    {
-      send_reply(sptr, (chptr ? ERR_NOTONCHANNEL : ERR_NOSUCHCHANNEL),
-                chptr ? chptr->chname : name);
-      continue;
-    }
-    if (IsModelessChannel(name))
-    {
+   int newtopic;
+   /* if +n and not @'d, return an error and ignore the topic */
+   if ((chptr->mode.mode & MODE_TOPICLIMIT) != 0 && !is_chan_op(sptr, chptr)) 
+   {
       send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname);
-      continue;
-    }
-    if (IsLocalChannel(name) && !MyUser(sptr))
-      continue;
-
-    if (!topic)                 /* only asking  for topic  */
-    {
-      if (chptr->topic[0] == '\0')
-       send_reply(sptr, RPL_NOTOPIC, chptr->chname);
-      else
-      {
-       send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
-       send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
-                  chptr->topic_time);
-      }
-    }
-    else if (((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
-        is_chan_op(sptr, chptr)) && topic)
-    {
-      /* setting a topic */
-      ircd_strncpy(chptr->topic, topic, TOPICLEN);
-      ircd_strncpy(chptr->topic_nick, sptr->name, NICKLEN);
-      chptr->topic_time = CurrentTime;
-      sendcmdto_serv_butone(sptr, CMD_TOPIC, cptr, "%H :%s", chptr,
-                           chptr->topic);
+      return;
+   }
+   /* Note if this is just a refresh of an old topic, and don't
+    * send it to all the clients to save bandwidth.  We still send
+    * it to other servers as they may have split and lost the topic.
+    */
+   newtopic=ircd_strncmp(chptr->topic,topic,TOPICLEN)==0;
+   /* setting a topic */
+   ircd_strncpy(chptr->topic, topic, TOPICLEN);
+   ircd_strncpy(chptr->topic_nick, sptr->name, NICKLEN);
+   chptr->topic_time = CurrentTime;
+   /* Fixed in 2.10.11: Don't propergate local topics */
+   if (!IsLocalChannel(chptr->chname))
+     sendcmdto_serv_butone(sptr, CMD_TOPIC, cptr, "%H :%s", chptr,
+                          chptr->topic);
+   if (newtopic)
       sendcmdto_channel_butserv(sptr, CMD_TOPIC, chptr, "%H :%s", chptr,
-                               chptr->topic);
-    }
-    else
-      send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname);
-  }
-  return 0;
+                                 chptr->topic);
+      /* if this is the same topic as before we send it to the person that
+       * set it (so they knew it went through ok), but don't bother sending
+       * it to everyone else on the channel to save bandwidth
+       */
+    else if (MyUser(sptr))
+      sendcmdto_one(sptr, CMD_TOPIC, sptr, "%H :%s", chptr, chptr->topic);     
 }
 
 /*
- * ms_topic - server message handler
+ * m_topic - generic message handler
  *
  * parv[0]        = sender prefix
  * parv[1]        = channel
  * parv[parc - 1] = topic (if parc > 2)
  */
-int ms_topic(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+int m_topic(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
   struct Channel *chptr;
   char *topic = 0, *name, *p = 0;
@@ -186,22 +155,26 @@ int ms_topic(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
   for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
   {
     chptr = 0;
-    if (!IsChannelName(name) || !(chptr = FindChannel(name)) ||
-        ((topic || SecretChannel(chptr)) && !find_channel_member(sptr, chptr)))
+    /* Does the channel exist */
+    if (!IsChannelName(name) || !(chptr = FindChannel(name)))
     {
-      send_reply(sptr, (chptr ? ERR_NOTONCHANNEL : ERR_NOSUCHCHANNEL),
-                chptr ? chptr->chname : name);
+       send_reply(sptr,ERR_NOSUCHCHANNEL,name);
+       continue;
+    }
+    /* Trying to check a topic outside a secret channel */
+    if ((topic || SecretChannel(chptr)) && !find_channel_member(sptr, chptr))
+    {
+      send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname);
       continue;
     }
+    /* Modeless Channels don't have topics */
     if (IsModelessChannel(name))
     {
       send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname);
       continue;
     }
-    if (IsLocalChannel(name) && !MyUser(sptr))
-      continue;
 
-    if (!topic)                 /* only asking  for topic  */
+    if (!topic)                 /* only asking for topic */
     {
       if (chptr->topic[0] == '\0')
        send_reply(sptr, RPL_NOTOPIC, chptr->chname);
@@ -212,93 +185,51 @@ int ms_topic(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
                   chptr->topic_time);
       }
     }
-    else if (((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
-        is_chan_op(sptr, chptr)) && topic)
-    {
-      /* setting a topic */
-      ircd_strncpy(chptr->topic, topic, TOPICLEN);
-      ircd_strncpy(chptr->topic_nick, sptr->name, NICKLEN);
-      chptr->topic_time = CurrentTime;
-      sendcmdto_serv_butone(sptr, CMD_TOPIC, cptr, "%H :%s", chptr,
-                           chptr->topic);
-      sendcmdto_channel_butserv(sptr, CMD_TOPIC, chptr, "%H :%s", chptr,
-                               chptr->topic);
-    }
-    else
-      send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname);
+    else 
+     do_settopic(sptr,cptr,chptr,topic);
   }
   return 0;
 }
 
-
-#if 0
 /*
- * m_topic
+ * ms_topic - generic message handler
  *
  * parv[0]        = sender prefix
  * parv[1]        = channel
- * parv[parc - 1] = topic (if parc > 2)
+ * parv[parc - 1] = topic
  */
-int m_topic(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+int ms_topic(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
   struct Channel *chptr;
   char *topic = 0, *name, *p = 0;
 
-  if (parc < 2)
+  if (parc < 3)
     return need_more_params(sptr, "TOPIC");
 
-  if (parc > 2)
-    topic = parv[parc - 1];
+  topic = parv[parc - 1];
 
   for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
   {
     chptr = 0;
-    if (!IsChannelName(name) || !(chptr = FindChannel(name)) ||
-        ((topic || SecretChannel(chptr)) && !find_channel_member(sptr, chptr)))
+    /* Does the channel exist */
+    if (!IsChannelName(name) || !(chptr = FindChannel(name)))
     {
-      sendto_one(sptr, err_str(chptr ? ERR_NOTONCHANNEL : ERR_NOSUCHCHANNEL), /* XXX DEAD */
-          me.name, parv[0], chptr ? chptr->chname : name);
-      continue;
+       send_reply(sptr,ERR_NOSUCHCHANNEL,name);
+       continue;
     }
+    /* Modeless Channels don't have topics */
     if (IsModelessChannel(name))
     {
-      sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0], /* XXX DEAD */
-          chptr->chname);
+      /* Protocol Violation? */
+      send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname);
       continue;
     }
+    /* Ignore requests for topics from remote servers */
     if (IsLocalChannel(name) && !MyUser(sptr))
+      /* Protocol Violation warning here? */
       continue;
 
-    if (!topic)                 /* only asking  for topic  */
-    {
-      if (chptr->topic[0] == '\0')
-        sendto_one(sptr, rpl_str(RPL_NOTOPIC), me.name, parv[0], chptr->chname); /* XXX DEAD */
-      else
-      {
-        sendto_one(sptr, rpl_str(RPL_TOPIC), /* XXX DEAD */
-            me.name, parv[0], chptr->chname, chptr->topic);
-        sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), /* XXX DEAD */
-            me.name, parv[0], chptr->chname,
-            chptr->topic_nick, chptr->topic_time);
-      }
-    }
-    else if (((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
-        is_chan_op(sptr, chptr)) && topic)
-    {
-      /* setting a topic */
-      ircd_strncpy(chptr->topic, topic, TOPICLEN);
-      ircd_strncpy(chptr->topic_nick, sptr->name, NICKLEN);
-      chptr->topic_time = CurrentTime;
-      sendto_serv_butone(cptr, "%s%s " TOK_TOPIC " %s :%s", /* XXX DEAD */
-          NumNick(sptr), chptr->chname, chptr->topic);
-      sendto_channel_butserv(chptr, sptr, ":%s TOPIC %s :%s", /* XXX DEAD */
-          parv[0], chptr->chname, chptr->topic);
-    }
-    else
-      sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), /* XXX DEAD */
-          me.name, parv[0], chptr->chname);
+    do_settopic(sptr,cptr,chptr,topic);
   }
   return 0;
 }
-#endif /* 0 */
-
index bf3de6df90b714b87bfa930f240466fd055f95b1..a347352c974a74dd99e888928aba849c2733ea0b 100644 (file)
@@ -471,7 +471,7 @@ static Numeric replyTable[] = {
 /* 217 */
   { RPL_STATSPLINE, "P %d %d %s %s", "217" },
 /* 218 */
-  { RPL_STATSYLINE, "%c %d %d %d %d %ld", "218" },
+  { RPL_STATSYLINE, "%c %d %d %d %d %ld %d", "218" },
 /* 219 */
   { RPL_ENDOFSTATS, "%c :End of /STATS report", "219" },
 /* 220 */