Author: Kev <klmitch@mit.edu>
authorKevin L. Mitchell <klmitch@mit.edu>
Thu, 30 Nov 2000 22:20:24 +0000 (22:20 +0000)
committerKevin L. Mitchell <klmitch@mit.edu>
Thu, 30 Nov 2000 22:20:24 +0000 (22:20 +0000)
Log message:

Finished most of the logging system (except for conversions to log_write())
by implementing the feature system, composed of F-lines, to set features
from the .conf, and the three new commands /set, /reset, and /get, to
manipulate feature settings on the fly.

Status: Stable, but expect bugs

Testing needed:

I'm too tired to try to figure out what sort of bugs might be hanging
around.  Beat on it for a while...

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

21 files changed:
ChangeLog
doc/example.conf
include/client.h
include/handlers.h
include/ircd_features.h [new file with mode: 0644]
include/ircd_log.h
include/msg.h
include/numeric.h
include/s_stats.h
ircd/Makefile.in
ircd/ircd_features.c [new file with mode: 0644]
ircd/ircd_log.c
ircd/m_get.c [new file with mode: 0644]
ircd/m_rehash.c
ircd/m_reset.c [new file with mode: 0644]
ircd/m_set.c [new file with mode: 0644]
ircd/m_stats.c
ircd/parse.c
ircd/s_conf.c
ircd/s_err.c
ircd/s_stats.c

index 94ab0d0b54257824259eec01600263d31eb1f853..5ab8c35e96ce0f906573268541296cb09a3d75d2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,60 @@
+2000-11-30  Kevin L. Mitchell  <klmitch@mit.edu>
+
+       * ircd/s_stats.c (report_feature_list): report features--only
+       local opers can see logging configuration, since it doesn't really
+       mean anything to users
+
+       * ircd/s_err.c: add reply messages for new feature subsystem
+
+       * ircd/s_conf.c: add F lines to .conf
+
+       * ircd/parse.c: add the message descriptions for /set, /reset, and
+       /get
+
+       * ircd/m_stats.c: add /stats f
+
+       * ircd/m_set.c (mo_set): implement /set
+
+       * ircd/m_reset.c (mo_reset): implement /reset
+
+       * ircd/m_rehash.c: /rehash m now flushes MOTD cache, and /rehash l
+       reopens log files (for log file rotation)
+
+       * ircd/m_get.c (mo_get): implement /get
+
+       * ircd/ircd_log.c: use int instead of void return value; add
+       log_report_features() and log_canon(); fix a function that
+       disappears if DEBUGMODE not #define'd
+
+       * ircd/ircd_features.c: functions to manipulate feature settings
+       either from the config file or with the new /set, /reset, and /get
+       commands
+
+       * ircd/Makefile.in: add new .c files, run make depend
+
+       * include/s_stats.h: declare report_feature_list() (/stats f
+       handler)
+
+       * include/numeric.h: add RPL_STATSFLINE, RPL_FEATURE,
+       ERR_NOFEATURE, ERR_BADLOGTYPE, ERR_BADLOGSYS, and ERR_BADLOGVALUE
+       reply numerics
+
+       * include/msg.h: add defines for SET, RESET, and GET
+
+       * include/ircd_log.h: add a function to canonicalize subsystem
+       names; change some void return values to int
+
+       * include/ircd_features.h: new features subsystem handles all the
+       manipulation of special features, like log files
+
+       * include/handlers.h: declare new mo_{s,res,g}et message handlers
+       for fiddling with features run-time
+
+       * include/client.h (SNO_DEFAULT): don't set SNO_DEBUG by default;
+       seemed like a good idea at the time...
+
+       * doc/example.conf: document new F lines
+
 2000-11-29  Kevin L. Mitchell  <klmitch@mit.edu>
 
        * ircd/s_debug.c: rewrite debug_init() and vdebug() in terms of
index aa29ead9a0390ad59ef5a4e50aec860a9bb51c9e..6fc165ad5017e937a1f34bfb5dc749f74eade6f1 100644 (file)
@@ -379,6 +379,66 @@ P:192.168.*:::6666
 # with the IP address 168.8.21.107
 #P:*:168.8.21.107:CH:7000
 
+# [F:lines]
+# IRC servers have a large number of options and features.  Most of these
+# are set at compile time through the use of #define's--see "make config"
+# for more details--but we are working to move many of these into the
+# configuration file.  Feature lines are the hook we're using for this.
+#
+# F:<key>:<value>[:<value>[...]]
+#
+# Currently, the only defined value for <key> is "LOG," and it allows you
+# to customize the settings of the logging architecture.  You can set the
+# default logging facility to, say, local7 (F:LOG:LOCAL7), or set a log
+# file for one of the subsystems (F:LOG:GLINE:FILE:gline.log).  More than
+# one subsystem can log to the same file without danger of interleaving.
+#
+# The currently defined subsystems are SYSTEM, CONFIG, OPERMODE (used by
+# /opmode and /clearmode), GLINE, JUPE, WHO (used by /whox), NETWORK
+# (connects and disconnects), OPERKILL, SERVKILL, OPER, OPERLOG, USERLOG,
+# RESOLVER, SOCKET, DEBUG, and OLDLOG.  You can set log files for these
+# subsystems to log to, or you can tell them to syslog their data, or
+# even send server notices.  You can do any of these in combination, but
+# you can't log to more than one file.  You can also set minimum log
+# levels per subsystem, if you wish.
+#
+# The format for LOG Feature lines is as follows:
+#
+# F:LOG:<facility>
+# F:LOG:<subsystem>:<type>[:<value>]
+#
+# The first sets the default facility for ircu to log to to <facility>.
+# Valid <facility> values are listed in the syslog(3) man page; just
+# remove the "LOG_" prefix.
+#
+# The list of subsystems is given above.  The valid values for <type> are
+# FILE, FACILITY, SNOMASK, and LEVEL, which respectively set the log file,
+# the syslog facility, a server notice mask value, and the minimum log
+# level.  If no <value> is given, or if <value> is empty, the default
+# value for that type is set.
+#
+# Valid <value>'s for the FACILITY type are the normal syslog values (with
+# the "LOG_" prefix removed) or the special values "NONE" (which specifies
+# that syslogging should not be attempted) and "DEFAULT" (which specifies
+# that the server-wide facility should be used); the default for all
+# subsystems is "NONE."
+#
+# Valid <value>'s for the SNOMASK type are OLDSNO, SERVKILL, OPERKILL,
+# HACK2, HACK3, UNAUTH, TCPCOMMON, TOOMANY, HACK4, GLINE, NETWORK,
+# IPMISMATCH, THROTTLE, OLDREALOP, and CONNEXIT, as well as the special
+# values NONE, which specifies that no server notices should be sent,
+# and DEBUG, which is only available if DEBUGMODE has been enabled.
+#
+# Valid <value>'s for the LEVEL type are CRIT, ERR, WARNING, NOTICE,
+# TRACE, INFO, and DEBUG.  Note that logs with level CRIT always result
+# in server notices to mask SNO_OLDSNO, and logs with level DEBUG always
+# send server notices to mask SNO_DEBUG.
+#
+# A couple of things to note: log settings are not reset to defaults prior
+# to a rehash; this means that if you delete F-lines and rehash, logs will
+# continue going to the same place.  Also, all subsystems are defaulted to
+# minimum log level INFO (or DEBUG if DEBUGMODE is #define'd).
+
 #
 # Well, you have now reached the end of this sample configuration file
 # If you have any questions, feel free to mail <doco-com@undernet.org>
index 271e3d6a8163ad469281ee6331e9ba3e8c3c2b8f..4253816144857ed413339adebb528a9870587bba 100644 (file)
@@ -306,7 +306,7 @@ struct Client {
 
 #define SNO_USER        (SNO_ALL & ~SNO_OPER)
 
-#define SNO_DEFAULT ((SNO_NETWORK|SNO_OPERKILL|SNO_GLINE|SNO_DEBUG)&SNO_ALL)
+#define SNO_DEFAULT (SNO_NETWORK|SNO_OPERKILL|SNO_GLINE)
 #define SNO_OPERDEFAULT (SNO_DEFAULT|SNO_HACK2|SNO_HACK4|SNO_THROTTLE|SNO_OLDSNO)
 #define SNO_OPER (SNO_CONNEXIT|SNO_OLDREALOP)
 #define SNO_NOISY (SNO_SERVKILL|SNO_UNAUTH)
index 9b991d5fdfaf12d5873cdf764be24989d4749f35..4779db79dc585716c7f77b79cc12052a25662301 100644 (file)
@@ -137,6 +137,7 @@ extern int mo_clearmode(struct Client*, struct Client*, int, char*[]);
 extern int mo_close(struct Client*, struct Client*, int, char*[]);
 extern int mo_connect(struct Client*, struct Client*, int, char*[]);
 extern int mo_die(struct Client*, struct Client*, int, char*[]);
+extern int mo_get(struct Client*, struct Client*, int, char*[]);
 extern int mo_gline(struct Client*, struct Client*, int, char*[]);
 extern int mo_info(struct Client*, struct Client*, int, char*[]);
 extern int mo_jupe(struct Client*, struct Client*, int, char*[]);
@@ -146,8 +147,10 @@ extern int mo_oper(struct Client*, struct Client*, int, char*[]);
 extern int mo_opmode(struct Client*, struct Client*, int, char*[]);
 extern int mo_privmsg(struct Client*, struct Client*, int, char*[]);
 extern int mo_rehash(struct Client*, struct Client*, int, char*[]);
+extern int mo_reset(struct Client*, struct Client*, int, char*[]);
 extern int mo_restart(struct Client*, struct Client*, int, char*[]);
 extern int mo_rping(struct Client*, struct Client*, int, char*[]);
+extern int mo_set(struct Client*, struct Client*, int, char*[]);
 extern int mo_settime(struct Client*, struct Client*, int, char*[]);
 extern int mo_squit(struct Client*, struct Client*, int, char*[]);
 extern int mo_stats(struct Client*, struct Client*, int, char*[]);
diff --git a/include/ircd_features.h b/include/ircd_features.h
new file mode 100644 (file)
index 0000000..c683721
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef INCLUDED_features_h
+#define INCLUDED_features_h
+/*
+ * IRC - Internet Relay Chat, include/features.h
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program 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, or (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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+struct Client;
+
+extern int feature_set(struct Client* from, const char* const* fields,
+                      int count);
+extern int feature_reset(struct Client* from, const char* const* fields,
+                        int count);
+extern int feature_get(struct Client* from, const char* const* fields,
+                      int count);
+
+#endif /* INCLUDED_features_h */
index bd3468cde89df46bb8bc71eef5985d341d3105cd..367343429591e0dee30ab22a5e2f909407766047 100644 (file)
@@ -82,19 +82,23 @@ extern void log_write_kill(const struct Client *victim,
 
 #define LOG_NOMASK     (LOG_NOSYSLOG | LOG_NOFILELOG | LOG_NOSNOTICE)
 
-extern void log_set_file(char *subsys, char *filename);
-extern char *log_get_file(char *subsys);
+extern char *log_canon(const char *subsys);
 
-extern void log_set_facility(char *subsys, char *facility);
-extern char *log_get_facility(char *subsys);
+extern int log_set_file(const char *subsys, const char *filename);
+extern char *log_get_file(const char *subsys);
 
-extern void log_set_snomask(char *subsys, char *facility);
-extern char *log_get_snomask(char *subsys);
+extern int log_set_facility(const char *subsys, const char *facility);
+extern char *log_get_facility(const char *subsys);
 
-extern void log_set_level(char *subsys, char *level);
-extern char *log_get_level(char *subsys);
+extern int log_set_snomask(const char *subsys, const char *facility);
+extern char *log_get_snomask(const char *subsys);
 
-extern void log_set_default(char *facility);
+extern int log_set_level(const char *subsys, const char *level);
+extern char *log_get_level(const char *subsys);
+
+extern int log_set_default(const char *facility);
 extern char *log_get_default(void);
 
+extern void log_feature_report(struct Client *to);
+
 #endif /* INCLUDED_ircd_log_h */
index df16388ad458b501a549032e1b775565f4619f84..0d4be4639b94e4f86a48bcde9dbbdeb078405cf2 100644 (file)
@@ -325,6 +325,15 @@ struct Client;
 #define MSG_POST                "POST"          /* POST */
 #define TOK_POST                "POST"
 
+#define MSG_SET                        "SET"           /* SET */
+#define TOK_SET                        "SET"
+
+#define MSG_RESET              "RESET"         /* RESE */
+#define TOK_RESET              "RESET"
+
+#define MSG_GET                        "GET"           /* GET */
+#define TOK_GET                        "GET"
+
 /*
  * Constants
  */
index 7cfda7479a15e383fd23e2d9ba717e91f9320e97..48c26a47fbe7c1eb3ceed09a84449ef6868a8b68 100644 (file)
@@ -104,6 +104,7 @@ extern const struct Numeric* get_error_numeric(int err);
 #define RPL_SERVLIST         234       /* unused */
 #define RPL_SERVLISTEND      235       /* unused */
 
+#define RPL_STATSFLINE       238       /* Undernet feature lines */
 /*      RPL_STATSIAUTH       239           IRCnet extension */
 /*      RPL_STATSVLINE       240           IRCnet extension */
 #define RPL_STATSLLINE       241       
@@ -155,7 +156,7 @@ extern const struct Numeric* get_error_numeric(int err);
 #define RPL_ENDOFGLIST       281        /* Undernet extension */
 #define RPL_JUPELIST         282        /* Undernet extension - jupe -Kev */
 #define RPL_ENDOFJUPELIST    283        /* Undernet extension - jupe -Kev */
-
+#define RPL_FEATURE         284        /* Undernet extension - features */
 /*      RPL_CHANINFO_HANDLE  285           aircd */
 /*      RPL_CHANINFO_USERS   286           aircd */
 /*      RPL_CHANINFO_CHOPS   287           aircd */
@@ -353,6 +354,11 @@ extern const struct Numeric* get_error_numeric(int err);
 #define ERR_NOOPERHOST       491
 /*      ERR_NOSERVICEHOST    492 ? */
 
+#define ERR_NOFEATURE       493        /* Undernet extension - features */
+#define ERR_BADLOGTYPE      494        /* Undernet extension - features */
+#define ERR_BADLOGSYS       495        /* Undernet extension - features */
+#define ERR_BADLOGVALUE             496        /* Undernet extension - features */
+
 #define ERR_ISOPERLCHAN      498        /* Undernet extension */
 
 #define ERR_UMODEUNKNOWNFLAG 501
index 49dfe0120950ee0c938dbed648fb1f549ed2d5b0..ecd5766da54c7fc0af444026a9890c269e9a55eb 100644 (file)
@@ -35,5 +35,6 @@ extern int hunt_stats(struct Client* cptr, struct Client* sptr, int parc, char*
 extern void report_crule_list(struct Client* to, int mask);
 extern void report_motd_list(struct Client* to);
 extern void report_deny_list(struct Client* to);
+extern void report_feature_list(struct Client* to);
 
 #endif /* INCLUDED_s_stats_h */
index 57bab57a9d49c840fcc81dc45b64f7b3240fd455..16da5134591ec6e97edde9a4426f286592e01051 100644 (file)
@@ -76,6 +76,7 @@ SRC = \
        hash.c \
        ircd.c \
        ircd_alloc.c \
+       ircd_features.c \
        ircd_log.c \
        ircd_osdep.c \
        ircd_relay.c \
@@ -101,6 +102,7 @@ SRC = \
        m_die.c \
        m_endburst.c \
        m_error.c \
+       m_get.c \
        m_gline.c \
        m_help.c \
        m_info.c \
@@ -129,10 +131,12 @@ SRC = \
        m_proto.c \
        m_quit.c \
        m_rehash.c \
+       m_reset.c \
        m_restart.c \
        m_rping.c \
        m_rpong.c \
        m_server.c \
+       m_set.c \
        m_settime.c \
        m_silence.c \
        m_squit.c \
diff --git a/ircd/ircd_features.c b/ircd/ircd_features.c
new file mode 100644 (file)
index 0000000..aac26e1
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * IRC - Internet Relay Chat, ircd/features.c
+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
+ *
+ * This program 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 1, or (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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#include "features.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_bsd.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "send.h"
+#include "struct.h"
+#include "support.h"
+#include "sys.h"    /* FALSE bleah */
+
+#include <assert.h>
+#include <string.h>
+
+static struct LogTypes {
+  char *type;
+  int (*set)(const char *, const char *);
+  char *(*get)(const char *);
+} logTypes[] = {
+  { "FILE", log_set_file, log_get_file },
+  { "FACILITY", log_set_facility, log_get_facility },
+  { "SNOMASK", log_set_snomask, log_get_snomask },
+  { "LEVEL", log_set_level, log_get_level },
+  { 0, 0, 0 }
+};
+
+static struct LogTypes *
+feature_log_desc(struct Client* from, const char *type)
+{
+  int i;
+
+  assert(0 != type);
+
+  for (i = 0; logTypes[i].type; i++) /* find appropriate descriptor */
+    if (!ircd_strcmp(type, logTypes[i].type))
+      return &logTypes[i];
+
+  Debug((DEBUG_ERROR, "Unknown log feature type \"%s\"", type));
+  if (from)
+    send_reply(from, ERR_BADLOGTYPE, type);
+  else
+    log_write(LS_CONFIG, L_ERROR, 0, "Unknown log feature type \"%s\"", type);
+
+  return 0; /* not found */
+}
+
+static void
+feature_log_set(struct Client* from, const char* const* fields, int count)
+{
+  struct LogTypes *desc;
+  char *subsys;
+
+  if (count < 2) { /* set default facility */
+    if (log_set_default(count < 1 ? 0 : fields[0])) {
+      assert(count >= 1); /* should always accept default */
+
+      if (from)
+       send_reply(from, ERR_BADLOGVALUE, fields[0]);
+      else
+       log_write(LS_CONFIG, L_ERROR, 0,
+                 "Bad value \"%s\" for default facility", fields[0]);
+    }
+  } else if (!(subsys = log_canon(fields[0]))) { /* no such subsystem */
+    if (from)
+      send_reply(from, ERR_BADLOGSYS, fields[0]);
+    else
+      log_write(LS_CONFIG, L_ERROR, 0,
+               "No such logging subsystem \"%s\"", fields[0]);
+  } else if ((desc = feature_log_desc(from, fields[1]))) { /* set value */
+    if ((*desc->set)(fields[0], count < 3 ? 0 : fields[2])) {
+      assert(count >= 3); /* should always accept default */
+
+      if (from)
+       send_reply(from, ERR_BADLOGVALUE, fields[2]);
+      else
+       log_write(LS_CONFIG, L_ERROR, 0,
+                 "Bad value \"%s\" for log type %s (subsystem %s)",
+                 fields[2], desc->type, subsys);
+    }
+  }
+}
+
+static void
+feature_log_reset(struct Client* from, const char* const* fields, int count)
+{
+  struct LogTypes *desc;
+  char *subsys;
+
+  assert(0 != from);
+
+  if (count < 1) /* reset default facility */
+    log_set_default(0);
+  else if (count < 2)
+    need_more_params(from, "RESET");
+  else if (!(subsys = log_canon(fields[0]))) /* no such subsystem */
+    send_reply(from, ERR_BADLOGSYS, fields[0]);
+  else if ((desc = feature_log_desc(from, fields[1]))) /* reset value */
+    (*desc->set)(fields[0], 0);
+}
+
+static void
+feature_log_get(struct Client* from, const char* const* fields, int count)
+{
+  struct LogTypes *desc;
+  char *value, *subsys;
+
+  assert(0 != from);
+
+  if (count < 1) /* return default facility */
+    send_reply(from, SND_EXPLICIT | RPL_FEATURE, ":Log facility: %s",
+              log_get_default());
+  else if (count < 2)
+    need_more_params(from, "GET");
+  else if (!(subsys = log_canon(fields[0]))) { /* no such subsystem */
+    send_reply(from, ERR_BADLOGSYS, fields[0]);
+  } else if ((desc = feature_log_desc(from, fields[1]))) {
+    if ((value = (*desc->get)(fields[0]))) /* send along value */
+      send_reply(from, SND_EXPLICIT | RPL_FEATURE,
+                ":Log %s for subsystem %s: %s", desc->type, subsys,
+                (*desc->get)(subsys));
+    else
+      send_reply(from, SND_EXPLICIT | RPL_FEATURE,
+                ":No log %s is set for subsystem %s", desc->type, subsys);
+  }
+}
+
+typedef void (*feature_call)(struct Client*, const char* const*, int);
+
+static struct FeatureDesc {
+  char *type;
+  feature_call set;   /* set feature values */
+  feature_call reset; /* reset feature values to defaults */
+  feature_call get;   /* get feature values */
+} features[] = {
+  { "LOG", feature_log_set, feature_log_reset, feature_log_get },
+  { 0, 0, 0, 0 }
+};
+
+static struct FeatureDesc *
+feature_desc(struct Client* from, const char *feature)
+{
+  int i;
+
+  assert(0 != feature);
+
+  for (i = 0; features[i].type; i++) /* find appropriate descriptor */
+    if (!ircd_strcmp(feature, features[i].type))
+      return &features[i];
+
+  Debug((DEBUG_ERROR, "Unknown feature \"%s\"", feature));
+  if (from)
+    send_reply(from, ERR_NOFEATURE, feature);
+  else
+    log_write(LS_CONFIG, L_ERROR, 0, "Unknown feature \"%s\"", feature);
+
+  return 0; /* not found */
+}
+
+int
+feature_set(struct Client* from, const char* const* fields, int count)
+{
+  struct FeatureDesc *feat;
+
+  if (count < 1) {
+    if (from)
+      need_more_params(from, "SET");
+    else
+      log_write(LS_CONFIG, L_ERROR, 0, "Not enough fields in F line");
+  } else if ((feat = feature_desc(from, fields[0])))
+    (*feat->set)(from, fields + 1, count - 1);
+
+  return 0;
+}
+
+int
+feature_reset(struct Client* from, const char* const* fields, int count)
+{
+  struct FeatureDesc *feat;
+
+  assert(0 != from);
+
+  if (count < 1)
+    need_more_params(from, "RESET");
+  else if ((feat = feature_desc(from, fields[0])))
+    (*feat->reset)(from, fields + 1, count - 1);
+
+  return 0;
+}
+
+int
+feature_get(struct Client* from, const char* const* fields, int count)
+{
+  struct FeatureDesc *feat;
+
+  assert(0 != from);
+
+  if (count < 1)
+    need_more_params(from, "GET");
+  else if ((feat = feature_desc(from, fields[0])))
+    (*feat->get)(from, fields + 1, count - 1);
+
+  return 0;
+}
index 8d2f251a415a3c84909495928a987d2de81aad3d..b8669a4a4450d342f43f656db7d3c91ca9e44150 100644 (file)
 #include "client.h"
 #include "config.h"
 #include "ircd_alloc.h"
+#include "ircd_reply.h"
 #include "ircd_snprintf.h"
 #include "ircd_string.h"
 #include "ircd.h"
+#include "numeric.h"
 #include "s_debug.h"
 #include "send.h"
 #include "struct.h"
@@ -248,25 +250,28 @@ log_debug_init(char *file)
   logDesc[LS_DEBUG].file = logInfo.dbfile; /* remember where it went */
 }
 
+#endif /* DEBUGMODE */
+
 /* set the debug log file */
-static void
-log_debug_file(char *file)
+static int
+log_debug_file(const char *file)
 {
+#ifdef DEBUGMODE
   assert(0 != file);
 
   /* If we weren't started with debugging enabled, or if we're using
    * the terminal, don't do anything at all.
    */
   if (!logInfo.dbfile || !logInfo.dbfile->file)
-    return;
+    return 1;
 
   MyFree(logInfo.dbfile->file); /* free old pathname */
   DupString(logInfo.dbfile->file, file); /* store new pathname */
 
   log_debug_reopen(); /* reopen the debug log */
-}
-
 #endif /* DEBUGMODE */
+  return 0;
+}
 
 /* called in place of open_log(), this stores the process name and prepares
  * for syslogging
@@ -498,7 +503,7 @@ log_file_destroy(struct LogFile *lf)
 
 /* finds a subsystem given its name */
 static struct LogDesc *
-log_find(char *subsys)
+log_find(const char *subsys)
 {
   int i;
 
@@ -512,9 +517,21 @@ log_find(char *subsys)
   return 0; /* not found */
 }
 
+/* canonicalize subsystem names */
+char *
+log_canon(const char *subsys)
+{
+  struct LogDesc *desc;
+
+  if (!(desc = log_find(subsys)))
+    return 0;
+
+  return desc->name;
+}
+
 /* find a level given its name */
 static enum LogLevel
-log_lev_find(char *level)
+log_lev_find(const char *level)
 {
   int i;
 
@@ -528,9 +545,20 @@ log_lev_find(char *level)
   return L_LAST_LEVEL; /* not found */
 }
 
+/* return a name for a level */
+static char *
+log_lev_name(enum LogLevel lev)
+{
+  assert(-1 < (int)lev);
+  assert((int)lev < L_LAST_LEVEL);
+  assert(lev == levelData[lev].level);
+
+  return levelData[lev].string;
+}
+
 /* find a facility given its name */
 static int
-log_fac_find(char *facility)
+log_fac_find(const char *facility)
 {
   int i;
 
@@ -544,9 +572,23 @@ log_fac_find(char *facility)
   return LOG_NOTFOUND; /* not found */
 }
 
+/* return a name for a facility */
+static char *
+log_fac_name(int fac)
+{
+  int i;
+
+  /* find the facility */
+  for (i = 0; facilities[i].name; i++)
+    if (facilities[i].facility == fac)
+      return facilities[i].name;
+
+  return 0; /* not found; should never happen */
+}
+
 /* find a snomask value given its name */
 static unsigned int
-log_sno_find(char *maskname)
+log_sno_find(const char *maskname)
 {
   int i;
 
@@ -560,24 +602,37 @@ log_sno_find(char *maskname)
   return SNO_NOTFOUND; /* not found */
 }
 
+/* return a name for a snomask value */
+static char *
+log_sno_name(unsigned int sno)
+{
+  int i;
+
+  /* find the snomask */
+  for (i = 0; masks[i].name; i++)
+    if (masks[i].snomask == sno)
+      return masks[i].name;
+
+  return 0; /* not found; should never happen */
+}
+
 /* set the log file for a subsystem */
-void
-log_set_file(char *subsys, char *filename)
+int
+log_set_file(const char *subsys, const char *filename)
 {
   struct LogDesc *desc;
 
   /* find subsystem */
   if (!(desc = log_find(subsys)))
-    return;
+    return 2;
 
   /* no change, don't go to the trouble of destroying and recreating */
   if (filename && !strcmp(desc->file->file, filename))
-    return;
+    return 0;
 
   /* debug log is special, since it has to be opened on fd 2 */
   if (desc->subsys == LS_DEBUG) {
-    log_debug_file(filename);
-    return;
+    return log_debug_file(filename);
   }
 
   if (desc->file) /* destroy previous entry... */
@@ -585,11 +640,13 @@ log_set_file(char *subsys, char *filename)
 
   /* set the file to use */
   desc->file = filename ? log_file_create(filename) : 0;
+
+  return 0;
 }
 
 /* get the log file for a subsystem */
 char *
-log_get_file(char *subsys)
+log_get_file(const char *subsys)
 {
   struct LogDesc *desc;
 
@@ -601,119 +658,116 @@ log_get_file(char *subsys)
 }
 
 /* set the facility for a subsystem */
-void
-log_set_facility(char *subsys, char *facility)
+int
+log_set_facility(const char *subsys, const char *facility)
 {
   struct LogDesc *desc;
   int fac;
 
   /* find subsystem */
   if (!(desc = log_find(subsys)))
-    return;
+    return 2;
 
   /* set syslog facility */
   if (EmptyString(facility))
     desc->facility = desc->def_fac;
   else if ((fac = log_fac_find(facility)) != LOG_NOTFOUND)
     desc->facility = fac;
+  else
+    return 1;
+
+  return 0;
 }
 
 /* get the facility for a subsystem */
 char *
-log_get_facility(char *subsys)
+log_get_facility(const char *subsys)
 {
   struct LogDesc *desc;
-  int i;
 
   /* find subsystem */
   if (!(desc = log_find(subsys)))
     return 0;
 
   /* find the facility's name */
-  for (i = 0; facilities[i].name; i++)
-    if (desc->facility == facilities[i].facility)
-      return facilities[i].name; /* found it... */
-
-  return 0; /* shouldn't ever happen */
+  return log_fac_name(desc->facility);
 }
 
 /* set the snomask value for a subsystem */
-void
-log_set_snomask(char *subsys, char *snomask)
+int
+log_set_snomask(const char *subsys, const char *snomask)
 {
   struct LogDesc *desc;
-  unsigned int sno;
+  unsigned int sno = SNO_DEFAULT;
 
   /* find subsystem */
   if (!(desc = log_find(subsys)))
-    return;
+    return 2;
 
   /* set snomask value */
   if (EmptyString(snomask))
     desc->snomask = desc->def_sno;
   else if ((sno = log_sno_find(snomask)) != SNO_NOTFOUND)
     desc->snomask = sno;
+  else
+    return 1;
+
+  return 0;
 }
 
 /* get the snomask value for a subsystem */
 char *
-log_get_snomask(char *subsys)
+log_get_snomask(const char *subsys)
 {
   struct LogDesc *desc;
-  int i;
 
   /* find subsystem */
   if (!(desc = log_find(subsys)))
     return 0;
 
   /* find the snomask value's name */
-  for (i = 0; masks[i].name; i++)
-    if (desc->snomask == masks[i].snomask)
-      return masks[i].name; /* found it... */
-
-  return 0; /* shouldn't ever happen */
+  return log_sno_name(desc->snomask);
 }
 
 /* set the level for a subsystem */
-void
-log_set_level(char *subsys, char *level)
+int
+log_set_level(const char *subsys, const char *level)
 {
   struct LogDesc *desc;
   enum LogLevel lev;
 
   /* find subsystem */
   if (!(desc = log_find(subsys)))
-    return;
+    return 2;
 
   /* set logging level */
   if (EmptyString(level))
     desc->level = L_DEFAULT;
   else if ((lev = log_lev_find(level)) != L_LAST_LEVEL)
     desc->level = lev;
+  else
+    return 1;
+
+  return 0;
 }
 
 /* get the level for a subsystem */
 char *
-log_get_level(char *subsys)
+log_get_level(const char *subsys)
 {
   struct LogDesc *desc;
-  int i;
 
   /* find subsystem */
   if (!(desc = log_find(subsys)))
     return 0;
 
   /* find the level's name */
-  for (i = 0; levelData[i].string; i++)
-    if (desc->level == levelData[i].level)
-      return levelData[i].string; /* found it... */
-
-  return 0; /* shouldn't ever happen */
+  return log_lev_name(desc->level);
 }
 
 /* set the overall default syslog facility */
-void
-log_set_default(char *facility)
+int
+log_set_default(const char *facility)
 {
   int fac, oldfac;
 
@@ -724,23 +778,50 @@ log_set_default(char *facility)
   else if ((fac = log_fac_find(facility)) != LOG_NOTFOUND &&
           fac != LOG_NONE && fac != LOG_DEFAULT)
     logInfo.facility = fac;
+  else
+    return 1;
 
   if (logInfo.facility != oldfac) {
     closelog(); /* reopen syslog with new facility setting */
     openlog(logInfo.procname, LOG_PID | LOG_NDELAY, logInfo.facility);
   }
+
+  return 0;
 }
 
 /* get the overall default syslog facility */
 char *
 log_get_default(void)
+{
+  /* find the facility's name */
+  return log_fac_name(logInfo.facility);
+}
+
+/* Report feature settings */
+void
+log_feature_report(struct Client *to)
 {
   int i;
 
-  /* find the facility's name */
-  for (i = 0; facilities[i].name; i++)
-    if (logInfo.facility == facilities[i].facility)
-      return facilities[i].name; /* found it... */
+  for (i = 0; i < LS_LAST_SYSTEM; i++) {
+    if (logDesc[i].file && logDesc[i].file->file) /* report file */
+      send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s FILE %s",
+                logDesc[i].name, logDesc[i].file->file);
+
+    if (logDesc[i].facility != logDesc[i].def_fac) /* report facility */
+      send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s FACILITY %s",
+                logDesc[i].name, log_fac_name(logDesc[i].facility));
+
+    if (logDesc[i].snomask != logDesc[i].def_sno) /* report snomask */
+      send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s SNOMASK %s",
+                logDesc[i].name, log_sno_name(logDesc[i].snomask));
+
+    if (logDesc[i].level != L_DEFAULT) /* report log level */
+      send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s LEVEL %s",
+                logDesc[i].name, log_lev_name(logDesc[i].level));
+  }
 
-  return 0; /* shouldn't ever happen */
+  if (logInfo.facility != LOG_USER) /* report default facility */
+    send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s",
+              log_fac_name(logInfo.facility));
 }
diff --git a/ircd/m_get.c b/ircd/m_get.c
new file mode 100644 (file)
index 0000000..3cdd6db
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_get.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program 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 1, or (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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * mo_get - oper message handler
+ */
+int mo_get(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return feature_get(sptr, (const char* const*)parv + 1, parc - 1);
+}
index de38a9cd1ab30ba67d08bc4573af2d593f54e9b8..01cfedcf36be544a20f55e5737f9913a10dd40e2 100644 (file)
@@ -92,6 +92,7 @@
 #include "ircd_log.h"
 #include "ircd_reply.h"
 #include "ircd_string.h"
+#include "motd.h"
 #include "numeric.h"
 #include "s_conf.h"
 #include "send.h"
 /*
  * mo_rehash - oper message handler
  * 
+ * parv[1] = 'm' flushes the MOTD cache and returns
+ * parv[1] = 'l' reopens the log files and returns
  * parv[1] = 'q' to not rehash the resolver (optional)
  */
 int mo_rehash(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
 #if defined(OPER_REHASH) || defined(LOCOP_REHASH)
-#ifndef LOCOP_REHASH
-  if (!MyUser(sptr) || !IsOper(sptr))
-#else
-#ifdef  OPER_REHASH
-  if (!MyUser(sptr) || !IsAnOper(sptr))
-#else
-  if (!MyUser(sptr) || !IsLocOp(sptr))
-#endif
-#endif
-  {
-    send_reply(sptr, ERR_NOPRIVILEGES);
-    return 0;
+  int flag = 0;
+
+# if !defined(OPER_REHASH) || !defined(LOCOP_REHASH)
+  if (
+#  ifdef OPER_REHASH
+      !IsOper(sptr)
+#  else
+      !IsLocOp(sptr)
+#  endif
+      )
+    return send_reply(sptr, ERR_NOPRIVILEGES);
+# endif
+
+  if (parc > 1) { /* special processing */
+    if (*parv[1] == 'm') {
+      send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Flushing MOTD cache");
+      motd_recache(); /* flush MOTD cache */
+      return 0;
+    } else if (*parv[1] == 'l') {
+      send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Reopening log files");
+      log_reopen(); /* reopen log files */
+      return 0;
+    } else if (*parv[1] == 'q')
+      flag = 2;
   }
+
   send_reply(sptr, RPL_REHASHING, configfile);
   sendto_opmask_butone(0, SNO_OLDSNO, "%C is rehashing Server config file",
                       sptr);
+
   ircd_log(L_INFO, "REHASH From %s\n", get_client_name(sptr, HIDE_IP));
-  return rehash(cptr, (parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0);
+
+  return rehash(cptr, flag);
 #endif /* defined(OPER_REHASH) || defined(LOCOP_REHASH) */
   return 0;
 }
 
-#if 0
-#if defined(OPER_REHASH) || defined(LOCOP_REHASH)
-/*
- * m_rehash
- */
-int m_rehash(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
-{
-#ifndef LOCOP_REHASH
-  if (!MyUser(sptr) || !IsOper(sptr))
-#else
-#ifdef  OPER_REHASH
-  if (!MyUser(sptr) || !IsAnOper(sptr))
-#else
-  if (!MyUser(sptr) || !IsLocOp(sptr))
-#endif
-#endif
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); /* XXX DEAD */
-    return 0;
-  }
-  sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], configfile); /* XXX DEAD */
-  sendto_ops("%s is rehashing Server config file", parv[0]); /* XXX DEAD */
-  ircd_log(L_INFO, "REHASH From %s\n", get_client_name(sptr, HIDE_IP));
-  return rehash(cptr, (parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0);
-}
-#endif
-#endif /* 0 */
-
diff --git a/ircd/m_reset.c b/ircd/m_reset.c
new file mode 100644 (file)
index 0000000..6a7981a
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_reset.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program 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 1, or (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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * mo_reset - oper message handler
+ */
+int mo_reset(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return feature_reset(sptr, (const char* const*)parv + 1, parc - 1);
+}
diff --git a/ircd/m_set.c b/ircd/m_set.c
new file mode 100644 (file)
index 0000000..76be0af
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_set.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program 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 1, or (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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * mo_set - oper message handler
+ */
+int mo_set(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return feature_set(sptr, (const char* const*)parv + 1, parc - 1);
+}
index de306a0f65e40d21252bc80dc90ab812b018d195..24f9cf05ac814142cfbe6d68e4f0d39c34fef55b 100644 (file)
@@ -270,6 +270,10 @@ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       if (0 == report_klines(sptr, (parc == 4) ? parv[3] : 0, 0))
         return 0;
       break;
+    case 'F':
+    case 'f':
+      report_feature_list(sptr);
+      break;
     case 'I':
     case 'i':
     {
@@ -501,6 +505,10 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       if (0 == report_klines(sptr, (parc > 3) ? parv[3] : 0, !IsOper(sptr)))
         return 0;
       break;
+    case 'F':
+    case 'f':
+      report_feature_list(sptr);
+      break;
     case 'I':
     case 'i':
     {
@@ -730,6 +738,10 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       if (0 == report_klines(sptr, (parc > 3) ? parv[3] : 0, 0))
         return 0;
       break;
+    case 'F':
+    case 'f':
+      report_feature_list(sptr);
+      break;
     case 'I':
     case 'i':
       {
index 7fb9571954dc73335d728507b2639c0a07c60229..2b44a4119486c524a46bf4d3b56e6333baa9f189 100644 (file)
@@ -531,6 +531,27 @@ struct Message msgtab[] = {
     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
     { m_proto, m_proto, m_proto, m_proto, m_ignore }
   },
+  {
+    MSG_SET,
+    TOK_SET,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, m_ignore, mo_set, m_ignore }
+  },
+  {
+    MSG_RESET,
+    TOK_RESET,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, m_ignore, mo_reset, m_ignore }
+  },
+  {
+    MSG_GET,
+    TOK_GET,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, m_ignore, mo_get, m_ignore }
+  },
   /* This command is an alias for QUIT during the unregistered part of
    * of the server.  This is because someone jumping via a broken web
    * proxy will send a 'POST' as their first command - which we will
index 8a457c8d54fd42e7a9bcbac90779f058775bf004..44d311b898d3f4eaa5b01f264ac5d4d1620a00e4 100644 (file)
@@ -25,6 +25,7 @@
 #include "class.h"
 #include "client.h"
 #include "crule.h"
+#include "ircd_features.h"
 #include "fileio.h"
 #include "gline.h"
 #include "hash.h"
@@ -1064,6 +1065,11 @@ int read_configuration_file(void)
       conf_add_crule(field_vector, field_count, CRULE_AUTO);
       aconf->status = CONF_ILLEGAL;
       break;
+    case 'F':                /* Feature line */
+    case 'f':
+      feature_set(0, &field_vector[1], field_count - 1);
+      aconf->status = CONF_ILLEGAL;
+      break;
     case 'H':                /* Hub server line */
     case 'h':
       aconf->status = CONF_HUB;
index a347352c974a74dd99e888928aba849c2733ea0b..4daadd77d2247e1d3fb7352b0cc54774b1b2d0d1 100644 (file)
@@ -511,7 +511,7 @@ static Numeric replyTable[] = {
 /* 237 */
   { 0 },
 /* 238 */
-  { 0 },
+  { RPL_STATSFLINE, "%c %s %s", "238" },
 /* 239 */
   { 0 },
 /* 240 */
@@ -603,7 +603,7 @@ static Numeric replyTable[] = {
 /* 283 */
   { RPL_ENDOFJUPELIST, ":End of Jupe List", "283" },
 /* 284 */
-  { 0 },
+  { RPL_FEATURE, 0, "284" },
 /* 285 */
   { 0 },
 /* 286 */
@@ -1025,13 +1025,13 @@ static Numeric replyTable[] = {
 /* 492 */
   { 0 },
 /* 493 */
-  { 0 },
+  { ERR_NOFEATURE, "%s :No such feature", "493" },
 /* 494 */
-  { 0 },
+  { ERR_BADLOGTYPE, "%s :No such log type", "494" },
 /* 495 */
-  { 0 },
+  { ERR_BADLOGSYS, "%s :No such log subsystem", "495" },
 /* 496 */
-  { 0 },
+  { ERR_BADLOGVALUE, "%s :Bad value for log type", "496" },
 /* 497 */
   { 0 },
 /* 498 */
index ba97f8aea999a0a50ef1bdd0145485185472c2de..68127b2a33d33d55534f549ffa1a214c2e18fdbb 100644 (file)
@@ -27,6 +27,7 @@
 #include "client.h"
 #include "ircd.h"
 #include "ircd_chattr.h"
+#include "ircd_log.h"
 #include "ircd_reply.h"
 #include "ircd_string.h"
 #include "listener.h"
@@ -71,6 +72,7 @@ const char *statsinfo[] = {
     "g - Global bans (G-lines).",
     "k - Local bans (K-Lines).",
     "o - Operator information.", 
+    "f - Feature settings.",
     "m - Message usage information.",
     "t - Local connection statistics (Total SND/RCV, etc).", 
     "w - Userload statistics.",
@@ -168,6 +170,15 @@ void report_deny_list(struct Client* to)
                p->hostmask, p->message, p->usermask);
 }
 
+/*
+ * {CONF_FEATURE, RPL_STATSFLINE, 'F'},
+ */
+void report_feature_list(struct Client* to)
+{
+  if (MyOper(to)) /* non-local opers don't need to know log config */
+    log_feature_report(to);
+}
+
 /* m_stats is so obnoxiously full of special cases that the different
  * hunt_server() possiblites were becoming very messy. It now uses a
  * switch() so as to be easier to read and update as params change. 
@@ -184,6 +195,8 @@ int hunt_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[],
       /* open to all, standard # of params */
     case 'U':
     case 'u':
+    case 'F':
+    case 'f':
       return hunt_server_cmd(sptr, CMD_STATS, cptr, 0, "%s :%C", 2, parc,
                             parv);