2001-01-02 Kevin L. Mitchell <klmitch@mit.edu>
+ * config/config-sh.in: get rid of DEFAULT_LIST_PARAMETER
+ compile-time option--now in features subsystem
+
+ * ircd/motd.c (motd_init): rework motd_init() to be called as the
+ notify function for MPATH and RPATH features (should probably
+ split it up a bit, though...)
+
+ * ircd/m_privs.c (mo_privs): if called with no parameters, return
+ privs of the caller, rather than an error
+
+ * ircd/m_list.c: pull usage message into its own function; pull
+ list parameter processing into its own function that does not
+ modify the contents of the parameter; add list_set_default() to
+ set the default list parameter (uses the notify hook); rework
+ m_list() to make use of these functions; removed dead code
+
+ * ircd/ircd_log.c (log_feature_mark): make sure to return 0, since
+ we have no notify handler
+
+ * ircd/ircd_features.c: add notify callback for notification of
+ value changes; give mark callback an int return value to indicate
+ whether or not to call the notify callback; fix up feature macros
+ for new notify callback; add DEFAULT_LIST_PARAM feature; rewrite
+ string handling in feature_set() to deal with def_str being a null
+ pointer; wrote feature_init() to set up all defaults appropriately
+
+ * ircd/ircd.c (main): call feature_init() instead of
+ feature_mark(), to avoid calling notify functions while setting up
+ defaults
+
+ * ircd/client.c: updated to deal with new privileges structure
+
+ * ircd/class.c: updated so init_class() can be called should one
+ of PINGFREQUENCY, CONNECTFREQUENCY, MAXIMUM_LINKS, or
+ DEFAULTMAXSENDQLENGTH be changed
+
+ * include/ircd_log.h: log_feature_mark() updated to fit with new
+ API changes
+
+ * include/ircd_features.h: added DEFAULT_LIST_PARAM feature and
+ feature_init() function (found necessary since adding the notify
+ stuff and notifying motd.c during start-up...before we defined
+ RPATH!)
+
+ * include/client.h: move privs around to enable addition of more
+ bits if necessary; based on the FD_* macros
+
+ * include/channel.h: declare list_set_default (actually located in
+ m_list.c *blanche*)
+
* ircd/s_user.c: retrieve MAXSILES and MAXSILELENGTH (now
AVBANLEN*MAXSILES) from features subsystem
int 'Maximum number of network connections (23 - (FD_SETSIZE-4))' MAXCONNECTIONS 252
int 'Nickname history length' NICKNAMEHISTORYLENGTH 800
endmenu
-
-mainmenu_option next_comment
-comment 'Server characteristics'
- bool 'Do you want to have a default LIST parameter' CONFIG_LIST y
- if [ "$CONFIG_LIST" = "y" ]; then
- string 'Give default LIST parameter' DEFAULT_LIST 'T<10'
- define_string DEFAULT_LIST_PARAM "$DEFAULT_LIST"
- else
- define_string DEFAULT_LIST "$DEFAULT_LIST"
- define_bool DEFAULT_LIST_PARAM n
- fi
-endmenu
the features known to the features subsystem. The order of entries in
this list must match precisely the order of features as listed in the
features[] table in ircd_features.c. There are four kinds of
-features, five different flags that can be set for features, and six
-different call-backs for more complex features.
+features, seven different flags that can be set for features, and
+seven different call-backs for more complex features.
Types of Features
Feature Flags
-There are five feature flags, one of which is used internally by the
-feature subsystem. Two of these flags, FEAT_OPER and FEAT_MYOPER, are
-used to select who can see the settings of those features; FEAT_OPER
-permits any operator anywhere on the network to examine the settings
-of a particular feature, whereas FEAT_MYOPER only permits operators
-local to a server to examine feature values. If neither of these two
-flags is specified, then any user may examine that feature's value.
-
-The other two flags only have any meaning for string values; they are
+There are seven feature flags, one of which is used internally by the
+feature subsystem. Three of these flags, FEAT_OPER, FEAT_MYOPER, and
+FEAT_NODISP, are used to select who can see the settings of those
+features; FEAT_OPER permits any operator anywhere on the network to
+examine the settings of a particular feature, whereas FEAT_MYOPER only
+permits operators local to a server to examine feature values, and
+FEAT_NODISP prohibits display of the feature value altogether. If
+none of these three flags are specified, then any user may examine
+that feature's value.
+
+Two other flags only have any meaning for string values; they are
FEAT_NULL, which is used to specify that a feature of type "STR" may
have a NULL value, and FEAT_CASE, which specifies that the feature is
-case sensitive--this may be used on file names, for example.
+case sensitive--this may be used on file names, for example. Note
+that if you give "0" as the default value for a feature, you must also
+set the FEAT_NULL flag.
+
+The remaining non-internal flag is FEAT_READ, which simply sets the
+feature to be read-only; a feature so marked may only be changed
+through the configuration file.
Marking Features
"Marking Features."
</function>
+<function>
+void feature_init(void);
+
+This function initializes the feature interface by setting the default
+values for all features correctly.
+</function>
+
<function>
void feature_report(struct Client* to);
</function>
<macro>
-#define F_N(type, flags, set, reset, get, unmark, mark, report)
+#define F_N(type, flags, set, reset, get, notify, unmark, mark, report)
This macro is used in the features[] table to simplify defining a
feature of type "NONE." The _type_ parameter is the name of the
</macro>
<macro>
-#define F_I(type, flags, v_int)
+#define F_I(type, flags, v_int, notify)
To define integer features, use the F_I() macro. The _type_ and
_flags_ parameters are as for F_N(), and the _v_int_ macro specifies
-the default value of the feature.
+the default value of the feature. The _notify_ parameter, if
+non-zero, will be called whenever the value of the feature changes.
</macro>
<macro>
-#define F_B(type, flags, v_int)
+#define F_B(type, flags, v_int, notify)
This macro is used for defining features of type "BOOL"; it is very
similar to F_I(), but _v_int_ should either 0 (for a "FALSE" value) or
-1 (for a "TRUE" value).
+1 (for a "TRUE" value). The _notify_ parameter, if non-zero, will be
+called whenever the value of the feature changes.
</macro>
<macro>
-#define F_S(type, flags, v_str)
+#define F_S(type, flags, v_str, notify)
Also similar to F_I(), F_S() defines features of type "STR." The
_flags_ argument may be the bitwise OR of one of FEAT_OPER or
FEAT_MYOPER with the special string flags FEAT_NULL and FEAT_CASE,
-which are described above in the section "Feature Flags."
+which are described above in the section "Feature Flags." The
+_notify_ parameter, if non-zero, will be called whenever the value of
+the feature changes. Note that FEAT_NULL *must* be set if the default
+string _v_str_ is set to NULL.
</macro>
<authors>
</authors>
<changelog>
+[2001-01-02 Kev] Add documentation for new flags and for the notify
+mechanism
+
[2000-12-18 Kev] Document the features API
</changelog>
extern char *pretty_mask(char *mask);
extern void del_invite(struct Client *cptr, struct Channel *chptr);
extern void list_next_channels(struct Client *cptr, int nr);
+extern void list_set_default(void); /* this belongs elsewhere! */
extern void modebuf_init(struct ModeBuf *mbuf, struct Client *source,
struct Client *connect, struct Channel *chan,
struct Whowas;
struct DNSReply;
struct hostent;
+struct Privs;
/*
* Structures
* source file, or in the source file itself (when only used in that file).
*/
+#define PRIV_CHAN_LIMIT 1 /* no channel limit on oper */
+#define PRIV_MODE_LCHAN 2 /* oper can mode local chans */
+#define PRIV_WALK_LCHAN 3 /* oper can walk thru local modes */
+#define PRIV_DEOP_LCHAN 4 /* no deop oper on local chans */
+#define PRIV_SHOW_INVIS 5 /* show local invisible users */
+#define PRIV_SHOW_ALL_INVIS 6 /* show all invisible users */
+#define PRIV_UNLIMIT_QUERY 7 /* unlimit who queries */
+
+#define PRIV_KILL 8 /* oper can KILL */
+#define PRIV_LOCAL_KILL 9 /* oper can local KILL */
+#define PRIV_REHASH 10 /* oper can REHASH */
+#define PRIV_RESTART 11 /* oper can RESTART */
+#define PRIV_DIE 12 /* oper can DIE */
+#define PRIV_GLINE 13 /* oper can GLINE */
+#define PRIV_LOCAL_GLINE 14 /* oper can local GLINE */
+#define PRIV_JUPE 15 /* oper can JUPE */
+#define PRIV_LOCAL_JUPE 16 /* oper can local JUPE */
+#define PRIV_OPMODE 17 /* oper can OP/CLEARMODE */
+#define PRIV_LOCAL_OPMODE 18 /* oper can local OP/CLEARMODE */
+#define PRIV_SET 19 /* oper can SET */
+#define PRIV_WHOX 20 /* oper can use /who x */
+#define PRIV_BADCHAN 21 /* oper can BADCHAN */
+#define PRIV_LOCAL_BADCHAN 22 /* oper can local BADCHAN */
+#define PRIV_SEE_CHAN 23 /* oper can see in secret chans */
+
+#define PRIV_PROPAGATE 24 /* propagate oper status */
+#define PRIV_DISPLAY 25 /* "Is an oper" displayed */
+#define PRIV_SEE_OPERS 26 /* display hidden opers */
+
+#define PRIV_LAST_PRIV 26 /* must be the same as the last priv */
+
+#define _PRIV_NBITS (8 * sizeof(unsigned long))
+
+#define _PRIV_IDX(priv) ((priv) / _PRIV_NBITS)
+#define _PRIV_BIT(priv) (1 << ((priv) % _PRIV_NBITS))
+
+struct Privs {
+ unsigned long priv_mask[(PRIV_LAST_PRIV / _PRIV_NBITS) + 1];
+};
+
struct Connection {
/*
* The following fields are allocated only for local clients
struct in_addr cli_ip; /* Real ip# NOT defined for remote servers! */
short cli_status; /* Client type */
unsigned char cli_local; /* local or remote client */
- unsigned int cli_privs; /* Oper privileges */
+ struct Privs cli_privs; /* Oper privileges */
char cli_name[HOSTLEN + 1]; /* Unique name of the client, nick or host */
char cli_username[USERLEN + 1]; /* username here now for auth stuff */
char cli_info[REALLEN + 1]; /* Free form additional client information */
#define SNO_OPER (SNO_CONNEXIT|SNO_OLDREALOP)
#define SNO_NOISY (SNO_SERVKILL|SNO_UNAUTH)
-#define PRIV_CHAN_LIMIT 0x00000001 /* no channel limit on oper */
-#define PRIV_MODE_LCHAN 0x00000002 /* oper can mode local chans */
-#define PRIV_WALK_LCHAN 0x00000004 /* oper can walk thru local modes */
-#define PRIV_DEOP_LCHAN 0x00000008 /* no deop oper on local chans */
-#define PRIV_SHOW_INVIS 0x00000010 /* show local invisible users */
-#define PRIV_SHOW_ALL_INVIS 0x00000020 /* show all invisible users */
-#define PRIV_UNLIMIT_QUERY 0x00000040 /* unlimit who queries */
-
-#define PRIV_KILL 0x00000080 /* oper can KILL */
-#define PRIV_LOCAL_KILL 0x00000100 /* oper can local KILL */
-#define PRIV_REHASH 0x00000200 /* oper can REHASH */
-#define PRIV_RESTART 0x00000400 /* oper can RESTART */
-#define PRIV_DIE 0x00000800 /* oper can DIE */
-#define PRIV_GLINE 0x00001000 /* oper can GLINE */
-#define PRIV_LOCAL_GLINE 0x00002000 /* oper can local GLINE */
-#define PRIV_JUPE 0x00004000 /* oper can JUPE */
-#define PRIV_LOCAL_JUPE 0x00008000 /* oper can local JUPE */
-#define PRIV_OPMODE 0x00010000 /* oper can OP/CLEARMODE */
-#define PRIV_LOCAL_OPMODE 0x00020000 /* oper can local OP/CLEARMODE */
-#define PRIV_SET 0x00040000 /* oper can SET */
-#define PRIV_WHOX 0x00080000 /* oper can use /who x */
-#define PRIV_BADCHAN 0x00100000 /* oper can BADCHAN */
-#define PRIV_LOCAL_BADCHAN 0x00200000 /* oper can local BADCHAN */
-#define PRIV_SEE_CHAN 0x00400000 /* oper can see in secret chans */
-
-#define PRIV_PROPAGATE 0x00800000 /* propagate oper status */
-#define PRIV_DISPLAY 0x01000000 /* "Is an oper" displayed */
-#define PRIV_SEE_OPERS 0x02000000 /* display hidden opers */
-
-#define HasPriv(cli, priv) (cli_privs(cli) & (priv))
+#define PrivSet(pset, priv) ((pset)->priv_mask[_PRIV_IDX(priv)] |= \
+ _PRIV_BIT(priv))
+#define PrivClr(pset, priv) ((pset)->priv_mask[_PRIV_IDX(priv)] &= \
+ ~(_PRIV_BIT(priv)))
+#define PrivHas(pset, priv) ((pset)->priv_mask[_PRIV_IDX(priv)] & \
+ _PRIV_BIT(priv))
+
+#define GrantPriv(cli, priv) (PrivSet(&(cli_privs(cli)), priv))
+#define RevokePriv(cli, priv) (PrivClr(&(cli_privs(cli)), priv))
+#define HasPriv(cli, priv) (PrivHas(&(cli_privs(cli)), priv))
typedef enum ShowIPType {
HIDE_IP,
FEAT_WALLOPS_OPER_ONLY,
FEAT_NODNS,
FEAT_RANDOM_SEED,
+ FEAT_DEFAULT_LIST_PARAM,
/* features that probably should not be touched */
FEAT_KILLCHASETIMELIMIT,
FEAT_LAST_F
};
+extern void feature_init(void);
+
extern int feature_set(struct Client* from, const char* const* fields,
int count);
extern int feature_reset(struct Client* from, const char* const* fields,
extern char *log_get_default(void);
extern void log_feature_unmark(void);
-extern void log_feature_mark(int flag);
+extern int log_feature_mark(int flag);
extern void log_feature_report(struct Client *to, int flag);
#endif /* INCLUDED_ircd_log_h */
#define BAD_PING ((unsigned int)-2)
#define BAD_CLIENT_CLASS ((unsigned int)-3)
-static struct ConnectionClass* connClassList;
+static struct ConnectionClass* connClassList = 0;
static unsigned int connClassAllocCount;
const struct ConnectionClass* get_class_list(void)
*/
void init_class(void)
{
- connClassList = (struct ConnectionClass*) make_class();
+ if (!connClassList)
+ connClassList = (struct ConnectionClass*) make_class();
ConClass(connClassList) = 0;
PingFreq(connClassList) = feature_int(FEAT_PINGFREQUENCY);
void
client_set_privs(struct Client* client)
{
- unsigned int privs = 0;
- unsigned int antiprivs = 0;
+ struct Privs privs;
+ struct Privs antiprivs;
int i;
- if (!IsAnOper(client)) {
- cli_privs(client) = 0; /* clear privilege mask */
+ memset(&privs, 0, sizeof(struct Privs));
+ memset(&privs, 0, sizeof(struct Privs));
+
+ if (!IsAnOper(client)) { /* clear privilege mask */
+ memset(&(cli_privs(client)), 0, sizeof(struct Privs));
return;
} else if (!MyConnect(client)) {
- cli_privs(client) = ~(PRIV_SET); /* everything but set... */
+ memset(&(cli_privs(client)), 255, sizeof(struct Privs));
+ PrivClr(&(cli_privs(client)), PRIV_SET);
return;
}
for (i = 0; feattab[i].priv; i++) {
if (feattab[i].flag == 0) {
if (feature_bool(feattab[i].feat))
- antiprivs |= feattab[i].priv;
+ PrivSet(&antiprivs, feattab[i].priv);
} else if (feattab[i].flag == ~0) {
if (!feature_bool(feattab[i].feat))
- antiprivs |= feattab[i].priv;
+ PrivSet(&antiprivs, feattab[i].priv);
} else if (cli_flags(client) & feattab[i].flag) {
if (feattab[i].feat == FEAT_LAST_F ||
feature_bool(feattab[i].feat))
- privs |= feattab[i].priv;
+ PrivSet(&privs, feattab[i].priv);
}
}
/* This is the end of the gross section */
- if (privs & PRIV_PROPAGATE)
- privs |= PRIV_DISPLAY; /* force propagating opers to display */
- else /* if they don't propagate oper status, prevent desyncs */
- antiprivs |= (PRIV_KILL | PRIV_GLINE | PRIV_JUPE | PRIV_OPMODE |
- PRIV_BADCHAN);
+ if (PrivHas(&privs, PRIV_PROPAGATE))
+ PrivSet(&privs, PRIV_DISPLAY); /* force propagating opers to display */
+ else { /* if they don't propagate oper status, prevent desyncs */
+ PrivSet(&antiprivs, PRIV_KILL);
+ PrivSet(&antiprivs, PRIV_GLINE);
+ PrivSet(&antiprivs, PRIV_JUPE);
+ PrivSet(&antiprivs, PRIV_OPMODE);
+ PrivSet(&antiprivs, PRIV_BADCHAN);
+ }
+
+ for (i = 0; i < _PRIV_IDX(PRIV_LAST_PRIV); i++)
+ privs.priv_mask[i] &= ~antiprivs.priv_mask[i];
- cli_privs(client) = privs & ~antiprivs;
+ cli_privs(client) = privs;
}
static struct {
cli_name(client));
for (i = 0; privtab[i].name; i++)
- if (cli_privs(client) & privtab[i].priv)
+ if (HasPriv(client, privtab[i].priv))
msgq_append(0, mb, "%s%s", found1++ ? " " : "", privtab[i].name);
send_buffer(to, mb, 0); /* send response */
daemon_init(thisServer.bootopt & BOOT_TTY);
setup_signals();
- feature_mark(); /* initialize features... */
+ feature_init(); /* initialize features... */
log_init(*argv);
set_nomem_handler(outofmemory);
*/
#include "config.h"
#include "ircd_features.h"
+#include "channel.h" /* list_set_default */
+#include "class.h"
#include "client.h"
#include "hash.h"
#include "ircd.h"
#include "ircd_reply.h"
#include "ircd_string.h"
#include "match.h"
+#include "motd.h"
#include "msg.h"
#include "numeric.h"
#include "numnicks.h"
typedef int (*feat_set_call)(struct Client*, const char* const*, int);
/* gets the value of a feature */
typedef void (*feat_get_call)(struct Client*, const char* const*, int);
+/* callback to notify of a feature's change */
+typedef void (*feat_notify_call)(void);
/* unmarks all sub-feature values prior to reading .conf */
typedef void (*feat_unmark_call)(void);
/* resets to defaults all currently unmarked values */
-typedef void (*feat_mark_call)(int);
+typedef int (*feat_mark_call)(int);
/* reports features as a /stats f list */
typedef void (*feat_report_call)(struct Client*, int);
feat_set_call set; /* set feature values */
feat_set_call reset; /* reset feature values to defaults */
feat_get_call get; /* get feature values */
+ feat_notify_call notify; /* notify of value change */
feat_unmark_call unmark; /* unmark all feature change values */
feat_mark_call mark; /* reset to defaults all unchanged features */
feat_report_call report; /* report feature values */
} features[] = {
-#define F_N(type, flags, set, reset, get, unmark, mark, report) \
+#define F_N(type, flags, set, reset, get, notify, unmark, mark, report) \
{ FEAT_ ## type, #type, FEAT_NONE | (flags), 0, 0, 0, 0, \
- (set), (reset), (get), (unmark), (mark), (report) }
-#define F_I(type, flags, v_int) \
+ (set), (reset), (get), (notify), (unmark), (mark), (report) }
+#define F_I(type, flags, v_int, notify) \
{ FEAT_ ## type, #type, FEAT_INT | (flags), 0, (v_int), 0, 0, \
- 0, 0, 0, 0, 0, 0 }
-#define F_B(type, flags, v_int) \
+ 0, 0, 0, (notify), 0, 0, 0 }
+#define F_B(type, flags, v_int, notify) \
{ FEAT_ ## type, #type, FEAT_BOOL | (flags), 0, (v_int), 0, 0, \
- 0, 0, 0, 0, 0, 0 }
-#define F_S(type, flags, v_str) \
+ 0, 0, 0, (notify), 0, 0, 0 }
+#define F_S(type, flags, v_str, notify) \
{ FEAT_ ## type, #type, FEAT_STR | (flags), 0, 0, 0, (v_str), \
- 0, 0, 0, 0, 0, 0 }
+ 0, 0, 0, (notify), 0, 0, 0 }
/* Misc. features */
F_N(LOG, FEAT_MYOPER, feature_log_set, feature_log_reset, feature_log_get,
- log_feature_unmark, log_feature_mark, log_feature_report),
- F_S(DOMAINNAME, 0, DOMAINNAME),
- F_B(RELIABLE_CLOCK, 0, 0),
- F_I(BUFFERPOOL, 0, 27000000),
- F_B(HAS_FERGUSON_FLUSHER, 0, 0),
- F_I(CLIENT_FLOOD, 0, 1024),
- F_I(SERVER_PORT, FEAT_OPER, 4400),
- F_B(NODEFAULTMOTD, 0, 1),
- F_B(KILL_IPMISMATCH, FEAT_OPER, 0),
- F_B(IDLE_FROM_MSG, 0, 1),
- F_B(HUB, 0, 0),
- F_B(WALLOPS_OPER_ONLY, 0, 0),
- F_B(NODNS, 0, 0),
- F_N(RANDOM_SEED, FEAT_NODISP, random_seed_set, 0, 0, 0, 0, 0),
+ 0, log_feature_unmark, log_feature_mark, log_feature_report),
+ F_S(DOMAINNAME, 0, DOMAINNAME, 0),
+ F_B(RELIABLE_CLOCK, 0, 0, 0),
+ F_I(BUFFERPOOL, 0, 27000000, 0),
+ F_B(HAS_FERGUSON_FLUSHER, 0, 0, 0),
+ F_I(CLIENT_FLOOD, 0, 1024, 0),
+ F_I(SERVER_PORT, FEAT_OPER, 4400, 0),
+ F_B(NODEFAULTMOTD, 0, 1, 0),
+ F_B(KILL_IPMISMATCH, FEAT_OPER, 0, 0),
+ F_B(IDLE_FROM_MSG, 0, 1, 0),
+ F_B(HUB, 0, 0, 0),
+ F_B(WALLOPS_OPER_ONLY, 0, 0, 0),
+ F_B(NODNS, 0, 0, 0),
+ F_N(RANDOM_SEED, FEAT_NODISP, random_seed_set, 0, 0, 0, 0, 0, 0),
+ F_S(DEFAULT_LIST_PARAM, FEAT_NULL, 0, list_set_default),
/* features that probably should not be touched */
- F_I(KILLCHASETIMELIMIT, 0, 30),
- F_I(MAXCHANNELSPERUSER, 0, 10),
- F_I(AVBANLEN, 0, 40),
- F_I(MAXBANS, 0, 30),
- F_I(MAXSILES, 0, 15),
- F_I(HANGONGOODLINK, 0, 300),
- F_I(HANGONRETRYDELAY, 0, 10),
- F_I(CONNECTTIMEOUT, 0, 90),
- F_I(TIMESEC, 0, 60),
- F_I(MAXIMUM_LINKS, 0, 1),
- F_I(PINGFREQUENCY, 0, 120),
- F_I(CONNECTFREQUENCY, 0, 600),
- F_I(DEFAULTMAXSENDQLENGTH, 0, 40000),
+ F_I(KILLCHASETIMELIMIT, 0, 30, 0),
+ F_I(MAXCHANNELSPERUSER, 0, 10, 0),
+ F_I(AVBANLEN, 0, 40, 0),
+ F_I(MAXBANS, 0, 30, 0),
+ F_I(MAXSILES, 0, 15, 0),
+ F_I(HANGONGOODLINK, 0, 300, 0),
+ F_I(HANGONRETRYDELAY, 0, 10, 0),
+ F_I(CONNECTTIMEOUT, 0, 90, 0),
+ F_I(TIMESEC, 0, 60, 0),
+ F_I(MAXIMUM_LINKS, 0, 1, init_class), /* reinit class 0 as needed */
+ F_I(PINGFREQUENCY, 0, 120, init_class),
+ F_I(CONNECTFREQUENCY, 0, 600, init_class),
+ F_I(DEFAULTMAXSENDQLENGTH, 0, 40000, init_class),
/* Some misc. default paths */
- F_S(MPATH, FEAT_CASE | FEAT_MYOPER, "ircd.motd"),
- F_S(RPATH, FEAT_CASE | FEAT_MYOPER, "remote.motd"),
- F_S(PPATH, FEAT_CASE | FEAT_MYOPER | FEAT_READ, "ircd.pid"),
+ F_S(MPATH, FEAT_CASE | FEAT_MYOPER, "ircd.motd", motd_init),
+ F_S(RPATH, FEAT_CASE | FEAT_MYOPER, "remote.motd", motd_init),
+ F_S(PPATH, FEAT_CASE | FEAT_MYOPER | FEAT_READ, "ircd.pid", 0),
/* Networking features */
- F_B(VIRTUAL_HOST, 0, 0),
- F_I(TOS_SERVER, 0, 0x08),
- F_I(TOS_CLIENT, 0, 0x08),
+ F_B(VIRTUAL_HOST, 0, 0, 0),
+ F_I(TOS_SERVER, 0, 0x08, 0),
+ F_I(TOS_CLIENT, 0, 0x08, 0),
/* features that affect all operators */
- F_B(CRYPT_OPER_PASSWORD, FEAT_MYOPER | FEAT_READ, 1),
- F_B(OPER_NO_CHAN_LIMIT, 0, 1),
- F_B(OPER_MODE_LCHAN, 0, 1),
- F_B(OPER_WALK_THROUGH_LMODES, 0, 0),
- F_B(NO_OPER_DEOP_LCHAN, 0, 0),
- F_B(SHOW_INVISIBLE_USERS, 0, 1),
- F_B(SHOW_ALL_INVISIBLE_USERS, 0, 1),
- F_B(UNLIMIT_OPER_QUERY, 0, 0),
- F_B(LOCAL_KILL_ONLY, 0, 0),
- F_B(CONFIG_OPERCMDS, 0, 1), /* XXX change default before release */
+ F_B(CRYPT_OPER_PASSWORD, FEAT_MYOPER | FEAT_READ, 1, 0),
+ F_B(OPER_NO_CHAN_LIMIT, 0, 1, 0),
+ F_B(OPER_MODE_LCHAN, 0, 1, 0),
+ F_B(OPER_WALK_THROUGH_LMODES, 0, 0, 0),
+ F_B(NO_OPER_DEOP_LCHAN, 0, 0, 0),
+ F_B(SHOW_INVISIBLE_USERS, 0, 1, 0),
+ F_B(SHOW_ALL_INVISIBLE_USERS, 0, 1, 0),
+ F_B(UNLIMIT_OPER_QUERY, 0, 0, 0),
+ F_B(LOCAL_KILL_ONLY, 0, 0, 0),
+ F_B(CONFIG_OPERCMDS, 0, 1, 0), /* XXX change default before release */
/* features that affect global opers on this server */
- F_B(OPER_KILL, 0, 1),
- F_B(OPER_REHASH, 0, 1),
- F_B(OPER_RESTART, 0, 1),
- F_B(OPER_DIE, 0, 1),
- F_B(OPER_GLINE, 0, 1),
- F_B(OPER_LGLINE, 0, 1),
- F_B(OPER_JUPE, 0, 1),
- F_B(OPER_LJUPE, 0, 1),
- F_B(OPER_OPMODE, 0, 1),
- F_B(OPER_LOPMODE, 0, 1),
- F_B(OPER_BADCHAN, 0, 0),
- F_B(OPER_LBADCHAN, 0, 0),
- F_B(OPER_SET, 0, 1),
- F_B(OPERS_SEE_IN_SECRET_CHANNELS, 0, 1),
+ F_B(OPER_KILL, 0, 1, 0),
+ F_B(OPER_REHASH, 0, 1, 0),
+ F_B(OPER_RESTART, 0, 1, 0),
+ F_B(OPER_DIE, 0, 1, 0),
+ F_B(OPER_GLINE, 0, 1, 0),
+ F_B(OPER_LGLINE, 0, 1, 0),
+ F_B(OPER_JUPE, 0, 1, 0),
+ F_B(OPER_LJUPE, 0, 1, 0),
+ F_B(OPER_OPMODE, 0, 1, 0),
+ F_B(OPER_LOPMODE, 0, 1, 0),
+ F_B(OPER_BADCHAN, 0, 0, 0),
+ F_B(OPER_LBADCHAN, 0, 0, 0),
+ F_B(OPER_SET, 0, 1, 0),
+ F_B(OPERS_SEE_IN_SECRET_CHANNELS, 0, 1, 0),
/* features that affect local opers on this server */
- F_B(LOCOP_KILL, 0, 0),
- F_B(LOCOP_REHASH, 0, 1),
- F_B(LOCOP_RESTART, 0, 0),
- F_B(LOCOP_DIE, 0, 0),
- F_B(LOCOP_LGLINE, 0, 1),
- F_B(LOCOP_LJUPE, 0, 1),
- F_B(LOCOP_LOPMODE, 0, 1),
- F_B(LOCOP_LBADCHAN, 0, 0),
- F_B(LOCOP_SET, 0, 0),
- F_B(LOCOP_SEE_IN_SECRET_CHANNELS, 0, 0),
+ F_B(LOCOP_KILL, 0, 0, 0),
+ F_B(LOCOP_REHASH, 0, 1, 0),
+ F_B(LOCOP_RESTART, 0, 0, 0),
+ F_B(LOCOP_DIE, 0, 0, 0),
+ F_B(LOCOP_LGLINE, 0, 1, 0),
+ F_B(LOCOP_LJUPE, 0, 1, 0),
+ F_B(LOCOP_LOPMODE, 0, 1, 0),
+ F_B(LOCOP_LBADCHAN, 0, 0, 0),
+ F_B(LOCOP_SET, 0, 0, 0),
+ F_B(LOCOP_SEE_IN_SECRET_CHANNELS, 0, 0, 0),
#undef F_S
#undef F_B
#undef F_I
#undef F_N
- { FEAT_LAST_F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ { FEAT_LAST_F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
/* Given a feature's identifier, look up the feature descriptor */
int
feature_set(struct Client* from, const char* const* fields, int count)
{
- int i;
+ int i, change = 0, tmp;
+ const char *t_str;
struct FeatureDesc *feat;
if (from && !HasPriv(from, PRIV_SET))
switch (feat->flags & FEAT_MASK) {
case FEAT_NONE:
if (feat->set && (i = (*feat->set)(from, fields + 1, count - 1))) {
+ change++; /* feature handler wants a change recorded */
+
if (i > 0) /* call the set callback and do marking */
feat->flags |= FEAT_MARK;
else /* i < 0 */
}
case FEAT_INT: /* an integer value */
+ tmp = feat->v_int; /* detect changes... */
+
if (count < 2) { /* reset value */
feat->v_int = feat->def_int;
feat->flags &= ~FEAT_MARK;
} else { /* ok, figure out the value and whether to mark it */
- feat->v_int = atoi(fields[1]);
+ feat->v_int = strtoul(fields[1], 0, 0);
if (feat->v_int == feat->def_int)
feat->flags &= ~FEAT_MARK;
else
feat->flags |= FEAT_MARK;
}
+
+ if (feat->v_int != tmp) /* check for change */
+ change++;
break;
case FEAT_BOOL: /* it's a boolean value--true or false */
+ tmp = feat->v_int; /* detect changes... */
+
if (count < 2) { /* reset value */
feat->v_int = feat->def_int;
feat->flags &= ~FEAT_MARK;
else
feat->flags |= FEAT_MARK;
}
+
+ if (feat->v_int != tmp) /* check for change */
+ change++;
break;
case FEAT_STR: /* it's a string value */
- if (count < 2 ||
- !(feat->flags & FEAT_CASE ? strcmp(fields[1], feat->def_str) :
- ircd_strcmp(fields[1], feat->def_str))) { /* reset to default */
- if (feat->v_str && feat->v_str != feat->def_str)
- MyFree(feat->v_str); /* free old value */
+ if (count < 2)
+ t_str = feat->def_str; /* changing to default */
+ else
+ t_str = *fields[1] ? fields[1] : 0;
+
+ if (!t_str && !(feat->flags & FEAT_NULL)) { /* NULL value permitted? */
+ if (from)
+ return send_reply(from, ERR_BADFEATVALUE, "NULL", feat->type);
+ else {
+ log_write(LS_CONFIG, L_ERROR, 0, "Bad value \"NULL\" for feature %s",
+ feat->type);
+ return 0;
+ }
+ }
+
+ if (t_str == feat->def_str ||
+ (t_str && feat->def_str &&
+ !(feat->flags & FEAT_CASE ? strcmp(t_str, feat->def_str) :
+ ircd_strcmp(t_str, feat->def_str)))) { /* resetting to default */
+ if (feat->v_str != feat->def_str) {
+ change++; /* change from previous value */
+
+ if (feat->v_str)
+ MyFree(feat->v_str); /* free old value */
+ }
+
feat->v_str = feat->def_str; /* very special... */
- feat->flags &= ~FEAT_MARK; /* unmark it */
- } else {
- if (!*fields[1]) { /* empty string translates to NULL */
- if (feat->flags & FEAT_NULL) { /* permitted? */
- if (feat->v_str && feat->v_str != feat->def_str)
- MyFree(feat->v_str); /* free old value */
- feat->v_str = 0; /* set it to NULL */
- } else if (from) /* hmmm...not permitted; report error */
- return send_reply(from, ERR_BADFEATVALUE, "NULL", feat->type);
- else {
- log_write(LS_CONFIG, L_ERROR, 0,
- "Bad value \"NULL\" for feature %s", feat->type);
- return 0;
- }
- } else if ((feat->flags & FEAT_CASE ?
- strcmp(fields[1], feat->v_str) :
- ircd_strcmp(fields[1], feat->v_str))) { /* new value */
- if (feat->v_str && feat->v_str != feat->def_str)
+ feat->flags &= ~FEAT_MARK;
+ } else if (!t_str) {
+ if (feat->v_str) {
+ change++; /* change from previous value */
+
+ if (feat->v_str != feat->def_str)
MyFree(feat->v_str); /* free old value */
- DupString(feat->v_str, fields[1]); /* store new value */
}
- feat->flags |= FEAT_MARK; /* mark it as having been touched */
- }
+ feat->v_str = 0; /* set it to NULL */
+
+ feat->flags |= FEAT_MARK;
+ } else if (!feat->v_str ||
+ (feat->flags & FEAT_CASE ? strcmp(t_str, feat->v_str) :
+ ircd_strcmp(t_str, feat->v_str))) { /* new value */
+ change++; /* change from previous value */
+
+ if (feat->v_str && feat->v_str != feat->def_str)
+ MyFree(feat->v_str); /* free old value */
+ DupString(feat->v_str, t_str); /* store new value */
+
+ feat->flags |= FEAT_MARK;
+ } else /* they match, but don't match the default */
+ feat->flags |= FEAT_MARK;
break;
}
+
+ if (change && feat->notify) /* call change notify function */
+ (*feat->notify)();
}
return 0;
int
feature_reset(struct Client* from, const char* const* fields, int count)
{
- int i;
+ int i, change = 0;
struct FeatureDesc *feat;
assert(0 != from);
switch (feat->flags & FEAT_MASK) {
case FEAT_NONE: /* None... */
if (feat->reset && (i = (*feat->reset)(from, fields + 1, count - 1))) {
+ change++; /* feature handler wants a change recorded */
+
if (i > 0) /* call reset callback and parse mark return */
feat->flags |= FEAT_MARK;
else /* i < 0 */
case FEAT_INT: /* Integer... */
case FEAT_BOOL: /* Boolean... */
+ if (feat->v_int != feat->def_int)
+ change++; /* change will be made */
+
feat->v_int = feat->def_int; /* set the default */
feat->flags &= ~FEAT_MARK; /* unmark it */
break;
case FEAT_STR: /* string! */
- if (feat->v_str && feat->v_str != feat->def_str)
- MyFree(feat->v_str); /* free old value */
+ if (feat->v_str != feat->def_str) {
+ change++; /* change has been made */
+ if (feat->v_str)
+ MyFree(feat->v_str); /* free old value */
+ }
+
feat->v_str = feat->def_str; /* set it to default */
feat->flags &= ~FEAT_MARK; /* unmark it */
break;
}
+
+ if (change && feat->notify) /* call change notify function */
+ (*feat->notify)();
}
return 0;
void
feature_mark(void)
{
- int i;
+ int i, change;
+
+ for (i = 0; features[i].type; i++) {
+ change = 0;
- for (i = 0; features[i].type; i++)
switch (features[i].flags & FEAT_MASK) {
case FEAT_NONE:
- if (features[i].mark) /* call the mark callback if necessary */
- (*features[i].mark)(features[i].flags & FEAT_MARK ? 1 : 0);
+ if (features[i].mark &&
+ (*features[i].mark)(features[i].flags & FEAT_MARK ? 1 : 0))
+ change++; /* feature handler wants a change recorded */
break;
case FEAT_INT: /* Integers or Booleans... */
case FEAT_BOOL:
- if (!(features[i].flags & FEAT_MARK)) /* not changed? */
+ if (!(features[i].flags & FEAT_MARK)) { /* not changed? */
+ if (features[i].v_int != features[i].def_int)
+ change++; /* we're making a change */
features[i].v_int = features[i].def_int;
+ }
break;
case FEAT_STR: /* strings... */
if (!(features[i].flags & FEAT_MARK)) { /* not changed? */
- if (features[i].v_str && features[i].v_str != features[i].def_str)
- MyFree(features[i].v_str); /* free old value */
+ if (features[i].v_str != features[i].def_str) {
+ change++; /* we're making a change */
+ if (features[i].v_str)
+ MyFree(features[i].v_str); /* free old value */
+ }
features[i].v_str = features[i].def_str;
}
break;
}
+
+ if (change && features[i].notify)
+ (*features[i].notify)(); /* call change notify function */
+ }
+}
+
+/* used to initialize the features subsystem */
+void
+feature_init(void)
+{
+ int i;
+
+ for (i = 0; features[i].type; i++) {
+ switch (features[i].flags & FEAT_MASK) {
+ case FEAT_NONE: /* you're on your own */
+ break;
+
+ case FEAT_INT: /* Integers or Booleans... */
+ case FEAT_BOOL:
+ features[i].v_int = features[i].def_int;
+ break;
+
+ case FEAT_STR: /* Strings */
+ features[i].v_str = features[i].def_str;
+ assert(features[i].def_str || (features[i].flags & FEAT_NULL));
+ break;
+ }
+ }
}
/* report all F-lines */
}
/* Reset unmarked fields to defaults... */
-void
+int
log_feature_mark(int flag)
{
int i;
if (!(logDesc[i].mark & LOG_MARK_LEVEL)) /* set default level */
logDesc[i].level = L_DEFAULT;
}
+
+ return 0; /* we don't have a notify handler */
}
/* Report feature settings */
#include "ircd.h"
#include "ircd_alloc.h"
#include "ircd_chattr.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
#include "ircd_reply.h"
#include "ircd_string.h"
#include "msg.h"
#include <stdlib.h>
#include <string.h>
+#define LPARAM_ERROR -1
+#define LPARAM_SUCCESS 0
+#define LPARAM_CHANNEL 1
+
+static struct ListingArgs la_init = {
+ 2147483647, /* max_time */
+ 0, /* min_time */
+ 4294967295U, /* max_users */
+ 0, /* min_users */
+ 0, /* topic_limits */
+ 2147483647, /* max_topic_time */
+ 0, /* min_topic_time */
+ 0 /* chptr */
+};
+
+static struct ListingArgs la_default = {
+ 2147483647, /* max_time */
+ 0, /* min_time */
+ 4294967295U, /* max_users */
+ 0, /* min_users */
+ 0, /* topic_limits */
+ 2147483647, /* max_topic_time */
+ 0, /* min_topic_time */
+ 0 /* chptr */
+};
+
+static int
+show_usage(struct Client *sptr)
+{
+ if (!sptr) { /* configuration file error... */
+ log_write(LS_CONFIG, L_ERROR, 0, "Invalid default list parameter");
+ return LPARAM_ERROR;
+ }
+
+ send_reply(sptr, RPL_LISTUSAGE,
+ "Usage: \002/QUOTE LIST\002 \037parameters\037");
+ send_reply(sptr, RPL_LISTUSAGE,
+ "Where \037parameters\037 is a space or comma seperated "
+ "list of one or more of:");
+ send_reply(sptr, RPL_LISTUSAGE,
+ " \002<\002\037max_users\037 ; Show all channels with less "
+ "than \037max_users\037.");
+ send_reply(sptr, RPL_LISTUSAGE,
+ " \002>\002\037min_users\037 ; Show all channels with more "
+ "than \037min_users\037.");
+ send_reply(sptr, RPL_LISTUSAGE,
+ " \002C<\002\037max_minutes\037 ; Channels that exist less "
+ "than \037max_minutes\037.");
+ send_reply(sptr, RPL_LISTUSAGE,
+ " \002C>\002\037min_minutes\037 ; Channels that exist more "
+ "than \037min_minutes\037.");
+ send_reply(sptr, RPL_LISTUSAGE,
+ " \002T<\002\037max_minutes\037 ; Channels with a topic last "
+ "set less than \037max_minutes\037 ago.");
+ send_reply(sptr, RPL_LISTUSAGE,
+ " \002T>\002\037min_minutes\037 ; Channels with a topic last "
+ "set more than \037min_minutes\037 ago.");
+ send_reply(sptr, RPL_LISTUSAGE,
+ "Example: LIST <3,>1,C<10,T>0 ; 2 users, younger than 10 "
+ "min., topic set.");
+
+ return LPARAM_ERROR; /* return error condition */
+}
+
+static int
+param_parse(struct Client *sptr, const char *param, struct ListingArgs *args,
+ int permit_chan)
+{
+ int is_time = 0;
+ char dir;
+ unsigned int val;
+
+ assert(0 != args);
+
+ if (!param) /* NULL param == default--no list param */
+ return LPARAM_SUCCESS;
+
+ while (1) {
+ switch (*param) {
+ case 'T':
+ case 't':
+ is_time++;
+ args->topic_limits = 1;
+ /*FALLTHROUGH*/
+
+ case 'C':
+ case 'c':
+ is_time++;
+ param++;
+ if (*param != '<' && *param != '>')
+ return show_usage(sptr);
+ /*FALLTHROUGH*/
+
+ case '<':
+ case '>':
+ dir = *(param++);
+
+ if (!IsDigit(*param)) /* must start with a digit */
+ return show_usage(sptr);
+
+ val = strtol(param, (char **)¶m, 10); /* convert it... */
+
+ if (*param != ',' && *param != ' ' && *param != '\0') /* check syntax */
+ return show_usage(sptr);
+
+ if (is_time && val < 80000000) /* Toggle UTC/offset */
+ val = TStime() - val * 60;
+
+ switch (is_time) {
+ case 0: /* number of users on channel */
+ if (dir == '<')
+ args->max_users = val;
+ else
+ args->min_users = val;
+ break;
+
+ case 1: /* channel topic */
+ if (dir == '<')
+ args->min_topic_time = val;
+ else
+ args->max_topic_time = val;
+ break;
+
+ case 2: /* channel creation time */
+ if (dir == '<')
+ args->min_time = val;
+ else
+ args->max_time = val;
+ break;
+ }
+ break;
+
+ default: /* channel name? */
+ if (!permit_chan || !IsChannelName(param))
+ return show_usage(sptr);
+
+ return LPARAM_CHANNEL;
+ break;
+ }
+
+ if (!*param) /* hit end of string? */
+ break;
+
+ param++;
+ }
+
+ return LPARAM_SUCCESS;
+}
+
+void
+list_set_default(void)
+{
+ la_default = la_init; /* start off with a clean slate... */
+
+ if (param_parse(0, feature_str(FEAT_DEFAULT_LIST_PARAM), &la_default, 0) !=
+ LPARAM_SUCCESS)
+ la_default = la_init; /* recover from error by switching to default */
+}
+
/*
* m_list - generic message handler
*
{
struct Channel *chptr;
char *name, *p = 0;
- int show_usage = 0, show_channels = 0, param;
- struct ListingArgs args = {
- 2147483647, /* max_time */
- 0, /* min_time */
- 4294967295U, /* max_users */
- 0, /* min_users */
- 0, /* topic_limits */
- 2147483647, /* max_topic_time */
- 0, /* min_topic_time */
- 0 /* chptr */
- };
+ int show_channels = 0, param;
+ struct ListingArgs args;
if (cli_listing(sptr)) /* Already listing ? */
{
}
if (parc < 2) /* No arguments given to /LIST ? */
- {
-#ifdef DEFAULT_LIST_PARAM
- static char *defparv[MAXPARA + 1];
- static int defparc = 0;
- static char lp[] = DEFAULT_LIST_PARAM;
- int i;
-
- /*
- * XXX - strtok used
- */
- if (!defparc)
- {
- char *s = lp, *t;
-
- defparc = 1;
- defparv[defparc++] = t = strtok(s, " ");
- while (t && defparc < MAXPARA)
- {
- if ((t = strtok(0, " ")))
- defparv[defparc++] = t;
- }
- }
- for (i = 1; i < defparc; i++)
- parv[i] = defparv[i];
- parv[i] = 0;
- parc = defparc;
-#endif /* DEFAULT_LIST_PARAM */
- }
+ args = la_default;
+ else {
+ args = la_init; /* initialize argument to blank slate */
- /* Decode command */
- for (param = 1; !show_usage && parv[param]; param++)
- {
- char *p = parv[param];
- do
- {
- int is_time = 0;
- switch (*p)
- {
- case 'T':
- case 't':
- is_time++;
- args.topic_limits = 1;
- /* Fall through */
- case 'C':
- case 'c':
- is_time++;
- p++;
- if (*p != '<' && *p != '>')
- {
- show_usage = 1;
- break;
- }
- /* Fall through */
- case '<':
- case '>':
- {
- p++;
- if (!IsDigit(*p))
- show_usage = 1;
- else
- {
- if (is_time)
- {
- time_t val = atoi(p);
- if (p[-1] == '<')
- {
- if (val < 80000000) /* Toggle UTC/offset */
- {
- /*
- * Demands that
- * 'TStime() - chptr->creationtime < val * 60'
- * Which equals
- * 'chptr->creationtime > TStime() - val * 60'
- */
- if (is_time == 1)
- args.min_time = TStime() - val * 60;
- else
- args.min_topic_time = TStime() - val * 60;
- }
- else if (is_time == 1) /* Creation time in UTC was entered */
- args.max_time = val;
- else /* Topic time in UTC was entered */
- args.max_topic_time = val;
- }
- else if (val < 80000000)
- {
- if (is_time == 1)
- args.max_time = TStime() - val * 60;
- else
- args.max_topic_time = TStime() - val * 60;
- }
- else if (is_time == 1)
- args.min_time = val;
- else
- args.min_topic_time = val;
- }
- else if (p[-1] == '<')
- args.max_users = atoi(p);
- else
- args.min_users = atoi(p);
- if ((p = strchr(p, ',')))
- p++;
- }
- break;
- }
- default:
- if (!IsChannelName(p))
- {
- show_usage = 1;
- break;
- }
- if (parc != 2) /* Don't allow a mixture of channels with <,> */
- show_usage = 1;
- show_channels = 1;
- p = 0;
- break;
+ for (param = 1; parv[param]; param++) { /* process each parameter */
+ switch (param_parse(sptr, parv[param], &args, parc != 2)) {
+ case LPARAM_ERROR: /* error encountered, usage already sent, return */
+ return 0;
+ break;
+
+ case LPARAM_CHANNEL: /* show channel instead */
+ show_channels++;
+ break;
+
+ case LPARAM_SUCCESS: /* parse succeeded */
+ break;
}
}
- while (!show_usage && p); /* p points after comma, or is NULL */
- }
-
- if (show_usage)
- {
- send_reply(sptr, RPL_LISTUSAGE,
- "Usage: \002/QUOTE LIST\002 \037parameters\037");
- send_reply(sptr, RPL_LISTUSAGE,
- "Where \037parameters\037 is a space or comma seperated "
- "list of one or more of:");
- send_reply(sptr, RPL_LISTUSAGE,
- " \002<\002\037max_users\037 ; Show all channels with less "
- "than \037max_users\037.");
- send_reply(sptr, RPL_LISTUSAGE,
- " \002>\002\037min_users\037 ; Show all channels with more "
- "than \037min_users\037.");
- send_reply(sptr, RPL_LISTUSAGE,
- " \002C<\002\037max_minutes\037 ; Channels that exist less "
- "than \037max_minutes\037.");
- send_reply(sptr, RPL_LISTUSAGE,
- " \002C>\002\037min_minutes\037 ; Channels that exist more "
- "than \037min_minutes\037.");
- send_reply(sptr, RPL_LISTUSAGE,
- " \002T<\002\037max_minutes\037 ; Channels with a topic last "
- "set less than \037max_minutes\037 ago.");
- send_reply(sptr, RPL_LISTUSAGE,
- " \002T>\002\037min_minutes\037 ; Channels with a topic last "
- "set more than \037min_minutes\037 ago.");
- send_reply(sptr, RPL_LISTUSAGE,
- "Example: LIST <3,>1,C<10,T>0 ; 2 users, younger than 10 "
- "min., topic set.");
- return 0;
}
send_reply(sptr, RPL_LISTSTART);
send_reply(sptr, RPL_LISTEND);
return 0;
}
-
-
-#if 0
-/*
- * m_list
- *
- * parv[0] = sender prefix
- * parv[1] = channel list or user/time limit
- * parv[2...] = more user/time limits
- */
-int m_list(struct Client* cptr, struct Client *sptr, int parc, char *parv[])
-{
- struct Channel *chptr;
- char *name, *p = 0;
- int show_usage = 0, show_channels = 0, param;
- struct ListingArgs args = {
- 2147483647, /* max_time */
- 0, /* min_time */
- 4294967295U, /* max_users */
- 0, /* min_users */
- 0, /* topic_limits */
- 2147483647, /* max_topic_time */
- 0, /* min_topic_time */
- 0 /* chptr */
- };
-
- if (sptr->listing) /* Already listing ? */
- {
- sptr->listing->chptr->mode.mode &= ~MODE_LISTED;
- MyFree(sptr->listing);
- sptr->listing = 0;
- sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, sptr->name); /* XXX DEAD */
- if (parc < 2)
- return 0; /* Let LIST abort a listing. */
- }
-
- if (parc < 2) /* No arguments given to /LIST ? */
- {
-#ifdef DEFAULT_LIST_PARAM
- static char *defparv[MAXPARA + 1];
- static int defparc = 0;
- static char lp[] = DEFAULT_LIST_PARAM;
- int i;
-
- if (!defparc)
- {
- char *s = lp, *t;
-
- defparc = 1;
- defparv[defparc++] = t = strtok(s, " ");
- while (t && defparc < MAXPARA)
- {
- if ((t = strtok(0, " ")))
- defparv[defparc++] = t;
- }
- }
- for (i = 1; i < defparc; i++)
- parv[i] = defparv[i];
- parv[i] = 0;
- parc = defparc;
-#endif /* DEFAULT_LIST_PARAM */
- }
-
- /* Decode command */
- for (param = 1; !show_usage && parv[param]; param++)
- {
- char *p = parv[param];
- do
- {
- int is_time = 0;
- switch (*p)
- {
- case 'T':
- case 't':
- is_time++;
- args.topic_limits = 1;
- /* Fall through */
- case 'C':
- case 'c':
- is_time++;
- p++;
- if (*p != '<' && *p != '>')
- {
- show_usage = 1;
- break;
- }
- /* Fall through */
- case '<':
- case '>':
- {
- p++;
- if (!IsDigit(*p))
- show_usage = 1;
- else
- {
- if (is_time)
- {
- time_t val = atoi(p);
- if (p[-1] == '<')
- {
- if (val < 80000000) /* Toggle UTC/offset */
- {
- /*
- * Demands that
- * 'TStime() - chptr->creationtime < val * 60'
- * Which equals
- * 'chptr->creationtime > TStime() - val * 60'
- */
- if (is_time == 1)
- args.min_time = TStime() - val * 60;
- else
- args.min_topic_time = TStime() - val * 60;
- }
- else if (is_time == 1) /* Creation time in UTC was entered */
- args.max_time = val;
- else /* Topic time in UTC was entered */
- args.max_topic_time = val;
- }
- else if (val < 80000000)
- {
- if (is_time == 1)
- args.max_time = TStime() - val * 60;
- else
- args.max_topic_time = TStime() - val * 60;
- }
- else if (is_time == 1)
- args.min_time = val;
- else
- args.min_topic_time = val;
- }
- else if (p[-1] == '<')
- args.max_users = atoi(p);
- else
- args.min_users = atoi(p);
- if ((p = strchr(p, ',')))
- p++;
- }
- break;
- }
- default:
- if (!IsChannelName(p))
- {
- show_usage = 1;
- break;
- }
- if (parc != 2) /* Don't allow a mixture of channels with <,> */
- show_usage = 1;
- show_channels = 1;
- p = 0;
- break;
- }
- }
- while (!show_usage && p); /* p points after comma, or is NULL */
- }
-
- if (show_usage)
- {
- sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
- "Usage: \002/QUOTE LIST\002 \037parameters\037");
- sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
- "Where \037parameters\037 is a space or comma seperated "
- "list of one or more of:");
- sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
- " \002<\002\037max_users\037 ; Show all channels with less "
- "than \037max_users\037.");
- sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
- " \002>\002\037min_users\037 ; Show all channels with more "
- "than \037min_users\037.");
- sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
- " \002C<\002\037max_minutes\037 ; Channels that exist less "
- "than \037max_minutes\037.");
- sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
- " \002C>\002\037min_minutes\037 ; Channels that exist more "
- "than \037min_minutes\037.");
- sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
- " \002T<\002\037max_minutes\037 ; Channels with a topic last "
- "set less than \037max_minutes\037 ago.");
- sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
- " \002T>\002\037min_minutes\037 ; Channels with a topic last "
- "set more than \037min_minutes\037 ago.");
- sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
- "Example: LIST <3,>1,C<10,T>0 ; 2 users, younger than 10 min., "
- "topic set.");
- return 0;
- }
-
- sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, parv[0]); /* XXX DEAD */
-
- if (!show_channels)
- {
- if (args.max_users > args.min_users + 1 && args.max_time > args.min_time &&
- args.max_topic_time > args.min_topic_time) /* Sanity check */
- {
- sptr->listing = (struct ListingArgs*) MyMalloc(sizeof(struct ListingArgs));
- assert(0 != sptr->listing);
- memcpy(sptr->listing, &args, sizeof(struct ListingArgs));
- if ((sptr->listing->chptr = GlobalChannelList)) {
- int m = GlobalChannelList->mode.mode & MODE_LISTED;
- list_next_channels(sptr, 64);
- GlobalChannelList->mode.mode |= m;
- return 0;
- }
- MyFree(sptr->listing);
- sptr->listing = 0;
- }
- sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]); /* XXX DEAD */
- return 0;
- }
-
- for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
- {
- chptr = FindChannel(name);
- if (chptr && ShowChannel(sptr, chptr) && sptr->user)
- sendto_one(sptr, rpl_str(RPL_LIST), me.name, parv[0], /* XXX DEAD */
- ShowChannel(sptr, chptr) ? chptr->chname : "*",
- chptr->users - number_of_zombies(chptr), chptr->topic);
- }
-
- sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]); /* XXX DEAD */
- return 0;
-}
-#endif /* 0 */
-
int i;
if (parc < 2)
- return need_more_params(sptr, "PRIVS");
+ return client_report_privs(sptr, sptr);
for (i = 1; i < parc; i++) {
for (name = ircd_strtok(&p, parv[i], " "); name;
struct Motd* other;
struct Motd* freelist;
struct MotdCache* cachelist;
-} MotdList;
+} MotdList = { 0, 0, 0, 0, 0 };
/* Create a struct Motd and initialize it */
static struct Motd *
void
motd_init(void)
{
+ if (MotdList.local) /* destroy old local... */
+ motd_destroy(MotdList.local);
+
MotdList.local = motd_create(0, feature_str(FEAT_MPATH), MOTD_MAXLINES);
motd_cache(MotdList.local); /* init local and cache it */
+ if (MotdList.remote) /* destroy old remote... */
+ motd_destroy(MotdList.remote);
+
MotdList.remote = motd_create(0, feature_str(FEAT_RPATH), MOTD_MAXREMOTE);
motd_cache(MotdList.remote); /* init remote and cache it */
-
- MotdList.other = 0; /* no T-lines processed yet */
-
- MotdList.freelist = 0;
- MotdList.cachelist = 0;
}
/* This routine adds a MOTD */