From 8189a0098c0ed9f480a2ce4e6fb898fc8abca162 Mon Sep 17 00:00:00 2001 From: "Kevin L. Mitchell" Date: Wed, 3 Jan 2001 03:03:04 +0000 Subject: [PATCH] Author: Kev Log message: Add notify functionality to features interface; featurize DEFAULT_LIST_PARAM, rewriting much of m_list in the process. Testing: It compiles and runs and appears to function properly; please brute-force. git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@354 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- ChangeLog | 50 ++++ config/config-sh.in | 12 - doc/api/features.txt | 61 +++-- include/channel.h | 1 + include/client.h | 83 +++--- include/ircd_features.h | 3 + include/ircd_log.h | 2 +- ircd/class.c | 5 +- ircd/client.c | 41 +-- ircd/ircd.c | 2 +- ircd/ircd_features.c | 323 ++++++++++++++--------- ircd/ircd_log.c | 4 +- ircd/m_list.c | 559 +++++++++++++--------------------------- ircd/m_privs.c | 2 +- ircd/motd.c | 13 +- 15 files changed, 576 insertions(+), 585 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2429d94..f124488 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,55 @@ 2001-01-02 Kevin L. Mitchell + * 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 diff --git a/config/config-sh.in b/config/config-sh.in index 405741a..71a7226 100644 --- a/config/config-sh.in +++ b/config/config-sh.in @@ -220,15 +220,3 @@ comment 'Configuration' 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 diff --git a/doc/api/features.txt b/doc/api/features.txt index d388540..a66e144 100644 --- a/doc/api/features.txt +++ b/doc/api/features.txt @@ -8,8 +8,8 @@ In the ircd_features.h header file is an enum Feature that lists all 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 @@ -35,18 +35,26 @@ functions, described below. 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 @@ -128,6 +136,13 @@ unchanged feature settings to their defaults. See the subsection on "Marking Features." + +void feature_init(void); + +This function initializes the feature interface by setting the default +values for all features correctly. + + void feature_report(struct Client* to); @@ -158,7 +173,7 @@ Use this function to retrieve strings values for features of type -#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 @@ -170,28 +185,33 @@ functions implementing the named call-back. -#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. -#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. -#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. @@ -199,5 +219,8 @@ Kev +[2001-01-02 Kev] Add documentation for new flags and for the notify +mechanism + [2000-12-18 Kev] Document the features API diff --git a/include/channel.h b/include/channel.h index 87c51e9..a8c4c3c 100644 --- a/include/channel.h +++ b/include/channel.h @@ -335,6 +335,7 @@ extern void send_channel_modes(struct Client *cptr, struct Channel *chptr); 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, diff --git a/include/client.h b/include/client.h index ba6217d..d6b4f49 100644 --- a/include/client.h +++ b/include/client.h @@ -55,6 +55,7 @@ struct User; struct Whowas; struct DNSReply; struct hostent; +struct Privs; /* * Structures @@ -64,6 +65,46 @@ struct hostent; * 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 @@ -138,7 +179,7 @@ struct Client { 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 */ @@ -405,36 +446,16 @@ struct Client { #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, diff --git a/include/ircd_features.h b/include/ircd_features.h index 04f03af..6c019bf 100644 --- a/include/ircd_features.h +++ b/include/ircd_features.h @@ -39,6 +39,7 @@ enum Feature { FEAT_WALLOPS_OPER_ONLY, FEAT_NODNS, FEAT_RANDOM_SEED, + FEAT_DEFAULT_LIST_PARAM, /* features that probably should not be touched */ FEAT_KILLCHASETIMELIMIT, @@ -108,6 +109,8 @@ enum Feature { 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, diff --git a/include/ircd_log.h b/include/ircd_log.h index 9c6b3b2..871534c 100644 --- a/include/ircd_log.h +++ b/include/ircd_log.h @@ -89,7 +89,7 @@ extern int log_set_default(const char *facility); 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 */ diff --git a/ircd/class.c b/ircd/class.c index feb5dd8..2a4d9cb 100644 --- a/ircd/class.c +++ b/ircd/class.c @@ -36,7 +36,7 @@ #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) @@ -68,7 +68,8 @@ void free_class(struct ConnectionClass* p) */ 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); diff --git a/ircd/client.c b/ircd/client.c index 0c74465..1ab61a4 100644 --- a/ircd/client.c +++ b/ircd/client.c @@ -152,15 +152,19 @@ static struct { 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; } @@ -169,26 +173,33 @@ client_set_privs(struct Client* client) 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 { @@ -222,7 +233,7 @@ client_report_privs(struct Client *to, struct Client *client) 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 */ diff --git a/ircd/ircd.c b/ircd/ircd.c index d60cc0c..27f6c8e 100644 --- a/ircd/ircd.c +++ b/ircd/ircd.c @@ -647,7 +647,7 @@ int main(int argc, char **argv) { daemon_init(thisServer.bootopt & BOOT_TTY); setup_signals(); - feature_mark(); /* initialize features... */ + feature_init(); /* initialize features... */ log_init(*argv); set_nomem_handler(outofmemory); diff --git a/ircd/ircd_features.c b/ircd/ircd_features.c index 9e6983b..30c13ea 100644 --- a/ircd/ircd_features.c +++ b/ircd/ircd_features.c @@ -20,6 +20,8 @@ */ #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" @@ -28,6 +30,7 @@ #include "ircd_reply.h" #include "ircd_string.h" #include "match.h" +#include "motd.h" #include "msg.h" #include "numeric.h" #include "numnicks.h" @@ -171,10 +174,12 @@ feature_log_get(struct Client* from, const char* const* fields, int count) 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); @@ -205,110 +210,112 @@ static struct FeatureDesc { 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 */ @@ -336,7 +343,8 @@ feature_desc(struct Client* from, const char *feature) 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)) @@ -354,6 +362,8 @@ feature_set(struct Client* from, const char* const* fields, int count) 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 */ @@ -362,19 +372,26 @@ feature_set(struct Client* from, const char* const* fields, int count) } 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; @@ -402,42 +419,69 @@ feature_set(struct Client* from, const char* const* fields, int count) 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; @@ -447,7 +491,7 @@ feature_set(struct Client* from, const char* const* fields, int count) int feature_reset(struct Client* from, const char* const* fields, int count) { - int i; + int i, change = 0; struct FeatureDesc *feat; assert(0 != from); @@ -464,6 +508,8 @@ feature_reset(struct Client* from, const char* const* fields, int count) 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 */ @@ -473,17 +519,27 @@ feature_reset(struct Client* from, const char* const* fields, int count) 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; @@ -553,29 +609,66 @@ feature_unmark(void) 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 */ diff --git a/ircd/ircd_log.c b/ircd/ircd_log.c index ab65f3b..53e8e00 100644 --- a/ircd/ircd_log.c +++ b/ircd/ircd_log.c @@ -828,7 +828,7 @@ log_feature_unmark(void) } /* Reset unmarked fields to defaults... */ -void +int log_feature_mark(int flag) { int i; @@ -854,6 +854,8 @@ log_feature_mark(int flag) 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 */ diff --git a/ircd/m_list.c b/ircd/m_list.c index 1a7db90..6007f7e 100644 --- a/ircd/m_list.c +++ b/ircd/m_list.c @@ -93,6 +93,8 @@ #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" @@ -104,6 +106,165 @@ #include #include +#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 * @@ -115,17 +276,8 @@ 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 */ - }; + int show_channels = 0, param; + struct ListingArgs args; if (cli_listing(sptr)) /* Already listing ? */ { @@ -138,156 +290,24 @@ int m_list(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) } 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); @@ -324,226 +344,3 @@ int m_list(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) 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 */ - diff --git a/ircd/m_privs.c b/ircd/m_privs.c index c2890a8..a5a307d 100644 --- a/ircd/m_privs.c +++ b/ircd/m_privs.c @@ -109,7 +109,7 @@ int mo_privs(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) 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; diff --git a/ircd/motd.c b/ircd/motd.c index f32bfb4..4617a36 100644 --- a/ircd/motd.c +++ b/ircd/motd.c @@ -53,7 +53,7 @@ static struct { 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 * @@ -326,16 +326,17 @@ motd_recache(void) 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 */ -- 2.20.1