Revision: 1885
http://undernet-ircu.svn.sourceforge.net/undernet-ircu/?rev=1885&view=rev
Author: klmitch
Date: 2008-10-04 03:29:22 +0000 (Sat, 04 Oct 2008)
Log Message:
-----------
Author: Kev <[EMAIL PROTECTED]>
Description:
Finish implementing the table registration and unregistration routines.
Also, implement mode_str_info(), for building the strings used in
RPL_MYINFO; mode_str_modes(), for building the strings used in the
CHANMODES parameter of RPL_ISUPPORT; and mode_str_prefix(), for building
the strings used in the PREFIX parameter of RPL_ISUPPORT.
Modified Paths:
--------------
ircu2/branches/mode/ChangeLog
ircu2/branches/mode/include/mode.h
ircu2/branches/mode/ircd/mode-compat.c
ircu2/branches/mode/ircd/mode.c
Modified: ircu2/branches/mode/ChangeLog
===================================================================
--- ircu2/branches/mode/ChangeLog 2008-10-03 03:49:25 UTC (rev 1884)
+++ ircu2/branches/mode/ChangeLog 2008-10-04 03:29:22 UTC (rev 1885)
@@ -1,3 +1,14 @@
+2008-10-03 Kevin L. Mitchell <[EMAIL PROTECTED]>
+
+ * include/mode.h: define MODE_DESC_CHECK() and MODE_LIST_CHECK()
+ macros; declare mode_str_info(), mode_str_modes(), and
+ mode_str_prefix()
+
+ * ircd/mode-compat.c: +o and +v also maintain lists...
+
+ * ircd/mode.c: implement *_reg() and *_unreg() routines; implement
+ mode_str_info(), mode_str_modes(), and mode_str_prefix()
+
2008-10-02 Kevin L. Mitchell <[EMAIL PROTECTED]>
* ircd/mode-compat.c: implement mode_compat_init()
Modified: ircu2/branches/mode/include/mode.h
===================================================================
--- ircu2/branches/mode/include/mode.h 2008-10-03 03:49:25 UTC (rev 1884)
+++ ircu2/branches/mode/include/mode.h 2008-10-04 03:29:22 UTC (rev 1885)
@@ -81,6 +81,9 @@
{ REGENT_INIT(MODE_DESC_MAGIC, (name)), (sw), (pfx), 0, (desc), \
(flags) | (((prio) & 0x0f) << 16) }
+/** Check the mode descriptor for validity. */
+#define MODE_DESC_CHECK(md) REGENT_CHECK((md), MODE_DESC_MAGIC)
+
/** Mode maintains a list. */
#define MDFLAG_LIST 0x80000000
/** Mode should not be propagated to other servers. */
@@ -166,6 +169,10 @@
(unreg_t) _mode_desc_unreg), (offset), \
KEYSPACE_INIT(MAX_MODES, 0, 0, 0) }
+/** Check the mode list for validity. */
+#define MODE_LIST_CHECK(ml) (REGTAB_CHECK(ml) && \
+ reg_magic(&(ml->ml_table)) == MODE_DESC_MAGIC)
+
/** Describes the set of modes set on a specific channel, user, etc. */
DECLARE_FLAGSET(ModeSet, MAX_MODES);
@@ -226,4 +233,11 @@
/* Initialize mode subsystem. */
extern void mode_init(void);
+/* Build mode list strings for RPL_MYINFO. */
+extern char* mode_str_info(modelist_t* ml, char* buf, int* len, int args);
+/* Build mode list strings for CHANMODES in RPL_ISUPPORT. */
+extern char* mode_str_modes(modelist_t* ml, char* buf, int* len);
+/* Build prefix string for PREFIX in RPL_ISUPPORT. */
+extern char* mode_str_prefix(modelist_t* ml, char* buf, int* len);
+
#endif /* INCLUDED_mode_h */
Modified: ircu2/branches/mode/ircd/mode-compat.c
===================================================================
--- ircu2/branches/mode/ircd/mode-compat.c 2008-10-03 03:49:25 UTC (rev
1884)
+++ ircu2/branches/mode/ircd/mode-compat.c 2008-10-04 03:29:22 UTC (rev
1885)
@@ -34,11 +34,11 @@
*/
modedesc_t _cmodes[] = {
MODE_DESC_INIT("CHANOP", 'o', "Channel operator.",
- MDPAR_ARG_CLI | MDPAR_TYPE_REQARG | MDPOL_AUTHZ_CHOP,
- '@', 15),
+ MDPAR_ARG_CLI | MDPAR_TYPE_REQARG | MDPOL_AUTHZ_CHOP |
+ MDFLAG_LIST, '@', 15),
MODE_DESC_INIT("VOICE", 'v', "Has voice.",
- MDPAR_ARG_CLI | MDPAR_TYPE_REQARG | MDPOL_AUTHZ_CHOP,
- '+', 0),
+ MDPAR_ARG_CLI | MDPAR_TYPE_REQARG | MDPOL_AUTHZ_CHOP |
+ MDFLAG_LIST, '+', 0),
MODE_DESC_INIT("PRIVATE", 'p', "Channel is private.",
MDPOL_AUTHZ_CHOP, 0, 0),
MODE_DESC_INIT("SECRET", 's', "Channel is secret.",
Modified: ircu2/branches/mode/ircd/mode.c
===================================================================
--- ircu2/branches/mode/ircd/mode.c 2008-10-03 03:49:25 UTC (rev 1884)
+++ ircu2/branches/mode/ircd/mode.c 2008-10-04 03:29:22 UTC (rev 1885)
@@ -26,24 +26,60 @@
#include "ircd_log.h"
#include "register.h"
+#include <string.h>
+
/** Initialize a mode list.
* @param[in] table Pointer to md_table.
- * @param[in] ml Mode list to verify.
+ * @param[in,out] ml Mode list to verify.
* @return 0 for valid mode list, non-zero otherwise.
*/
static int
ml_reg(regtab_t* table, modelist_t* ml)
{
+ /* Sanity-check the mode list */
+ if (reg_magic(&ml->ml_table) != MODE_DESC_MAGIC ||
+ reg_reg(&ml->ml_table) != _mode_desc_reg ||
+ reg_unreg(&ml->ml_table) != _mode_desc_unreg)
+ return -2;
+
+ /* Initialize the keyspace and the maps */
+ ks_init(&ml->ml_keyspace, MAX_MODES, 0, 0, ml);
+ memset(&ml->ml_smap, 0, sizeof(mode_desc_t*) * 256);
+ memset(&ml->ml_mmap, 0, sizeof(mode_desc_t*) * MAX_MODES);
+
+ return 0; /* all set! */
}
+/** Remove all existing mode descriptors from a mode list.
+ * @param[in,out] ml Pointer to modelist_t.
+ * @param[in,out] md Pointer to modedesc_t.
+ * @param[in] extra Extra pointer passed to regtab_iter().
+ * @return 0 to continue iteration.
+ */
+static int
+ml_unreg_flush(modelist_t* ml, modedesc_t* md, void* extra)
+{
+ /* unregister the mode descriptor */
+ unregtab(ml, md);
+
+ return 0;
+}
+
/** Clean up a mode list.
* @param[in] table Pointer to md_table.
- * @param[in] ml Mode list to flush.
+ * @param[in,out] ml Mode list to flush.
* @return 0 to accept unregistration.
*/
static int
ml_unreg(regtab_t* table, modelist_t* ml)
{
+ /* Remove all descriptors from the table */
+ regtab_iter(&ml->ml_table, (regiter_t) ml_unreg_flush, 0);
+
+ /* Clean up the keyspace and clear the maps */
+ ks_clean(&ml->ml_keyspace);
+ memset(&ml->ml_smap, 0, sizeof(mode_desc_t*) * 256);
+ memset(&ml->ml_mmap, 0, sizeof(mode_desc_t*) * MAX_MODES);
}
/** Table of mode lists. */
@@ -51,23 +87,52 @@
(reg_t) ml_reg, (unreg_t) ml_unreg);
/** Assign mode and add to appropriate tables.
- * @param[in] table Pointer to mode list.
- * @param[in] md Mode descriptor to add.
+ * @param[in,out] ml Pointer to mode list.
+ * @param[in,out] md Mode descriptor to add.
* @return 0 for valid mode descriptor, non-zero otherwise.
*/
int
-_mode_desc_reg(regtab_t* table, modedesc_t* md)
+_mode_desc_reg(modelist_t* ml, modedesc_t* md)
{
+ /* First, verify that the mode descriptor is valid */
+ if (!md->md_switch)
+ return -2;
+
+ /* Do we already have that switch registered? */
+ if (ml->ml_smap[md->md_switch])
+ return -3;
+
+ /* OK, let's reserve a mode from the keyspace */
+ if ((md->md_mode = ks_reserve(&ml->ml_keyspace)) == KEY_INVKEY)
+ return 1;
+
+ /* Enter the mode into the modelist maps */
+ ml->ml_smap[md->md_switch] = md;
+ ml->ml_mmap[md->md_mode] = md;
+
+ return 0;
}
/** Release mode and remove from tables.
- * @param[in] table Pointer to mode list.
+ * @param[in,out] ml Pointer to mode list.
* @param[in] md Mode descriptor to remove.
* @return 0 to accept unregistration.
*/
int
-_mode_desc_unreg(regtab_t* table, modedesc_t* md)
+_mode_desc_unreg(modelist_t* ml, modedesc_t* md)
{
+ /* Make sure the mode really is in the list... */
+ if (ml->ml_smap[md->md_switch] != md || ml->ml_mmap[md->md_mode] != md)
+ return -1;
+
+ /* Clear the modelist map entries */
+ ml->ml_smap[md->md_switch] = 0;
+ ml->ml_mmap[md->md_mode] = 0;
+
+ /* Return the key to the keyspace */
+ ks_release(&ml->ml_keyspace, md->md_mode);
+
+ return 0;
}
/** Initialize mode subsystem. */
@@ -76,3 +141,251 @@
{
reg(REG_TABLE, &md_table);
}
+
+/** Current state of informative mode string buffer. */
+struct info_state {
+ char* buf; /**< String buffer. */
+ int size; /**< Size of buffer. */
+ int len; /**< Current length of buffer. */
+ int args; /**< If true, skip modes without arguments. */
+};
+
+/** Determine if a specific mode should be added to the informative
+ * mode string.
+ * @param[in] table Registration table modedesc_t is in.
+ * @param[in] md Mode descriptor.
+ * @param[in,out] is Info string state.
+ * @return 0 to continue iteration.
+ */
+static int
+mi_build(regtab_t* table, modedesc_t* md, struct info_state *is)
+{
+ assert(MODE_DESC_CHECK(md));
+
+ /* Check if we're including this mode */
+ if (!(md->md_flags & MDFLAG_ARGEXTENDED) &&
+ (md->md_flags & MDFLAG_VIS_MASK) < MDFLAG_VIS_SERV &&
+ (!is->args || (md->md_flags & MDPAR_TYPE_MASK) <= MDPAR_TYPE_OPTARG))
+ /* Add this mode to the buffer */
+ is->buf[is->len++] = md->md_switch;
+
+ return is->len >= is->size;
+}
+
+/** Assemble informative mode string for RPL_MYINFO.
+ * @param[in] ml Mode list to build mode string from.
+ * @param[out] buf Buffer in which to build informative mode string.
+ * @param[in,out] len Size of buffer; on return, length of string.
+ * @param[in] args If 1, select only modes with parameters.
+ * @return Buffer containing informative mode string.
+ */
+char*
+mode_str_info(modelist_t* ml, char* buf, int* len, int args)
+{
+ struct info_state is = { buf, 0, 0, args };
+
+ assert(MODE_LIST_CHECK(ml));
+ assert(buf);
+ assert(len);
+
+ /* Set up the full info */
+ is.size = *len;
+
+ /* Now, let's iterate over all the mode descriptors */
+ if (regtab_iter(&ml->ml_table, (regiter_t) mi_build, &is))
+ return 0; /* some kind of failure occurred */
+
+ /* Terminate the buffer and store the new size */
+ is.buf[is.len] = '\0';
+ *len = is.len;
+
+ return is.buf; /* return the buffer */
+}
+
+/** Current state of mode description accumulation. */
+struct mode_state {
+ char* buf; /**< String buffer. */
+ int size; /**< Size of buffer. */
+ int len; /**< Current length of buffer. */
+ char* types[4]; /**< Pointers to string components. */
+};
+
+/** Type of mode. */
+enum mode_type {
+ TYPE_A, /**< Type A mode--maintains a list. */
+ TYPE_B, /**< Type B mode--always has an argument. */
+ TYPE_C, /**< Type C mode--only has an argument when set. */
+ TYPE_D /**< Type D mode--no argument. */
+};
+
+/** Add specific modes to the appropriate string component.
+ * @param[in] table Registration table modedesc_t is in.
+ * @param[in] md Mode descriptor.
+ * @param[in,out] ms String buffer state.
+ * @return 0 to continue iteration.
+ */
+static int
+mm_build(regtab_t* table, modedesc_t* md, struct mode_state *ms)
+{
+ enum mode_type type;
+
+ assert(MODE_DESC_CHECK(md));
+
+ /* Check if we need to omit this mode */
+ if ((md->md_flags & MDFLAG_ARGEXTENDED) ||
+ (md->md_flags & MDFLAG_VIS_MASK) >= MDFLAG_VIS_SERV ||
+ md->md_prefix)
+ return 0; /* skip this one */
+
+ /* Check the length... */
+ if (ms.len + 1 <= ms.size)
+ return -1;
+
+ /* Figure out which type of mode this is. */
+ if (md->md_flags & MDFLAG_LIST)
+ type = TYPE_A;
+ else
+ switch (md->md_flags & MDPAR_TYPE_MASK) {
+ case MDPAR_TYPE_SWITCH: /* plain switch */
+ case MDPAR_TYPE_OPTARG: /* shouldn't happen, but treat like plain switch */
+ type = TYPE_D;
+ break;
+
+ case MDPAR_TYPE_ADDARG: /* only has an argument when set */
+ type = TYPE_C;
+ break;
+
+ case MDPAR_TYPE_REQARG: /* requires an argument */
+ type = TYPE_B;
+ break;
+
+ default: /* uh... */
+ return 0;
+ break;
+ }
+
+ /* OK, let's shift the string over one position */
+ memmove(ms.types[type] + 1, ms.types[type],
+ ms.len + 1 - (ms.types[type] - ms.buf));
+
+ /* add this mode to the string */
+ *ms.types[type] = md->md_switch;
+
+ /* shift up the component pointers... */
+ for (; type <= TYPE_D; type++)
+ ms.types[type]++;
+
+ return 0;
+}
+
+/** Assemble string for CHANMODES component of RPL_ISUPPORT.
+ * @param[in] ml Mode list to build mode string from.
+ * @param[out] buf Buffer in which to build the string.
+ * @param[in,out] len Size of buffer; on return, length of string.
+ * @return Buffer containing modes string.
+ */
+char*
+mode_str_modes(modelist_t* ml, char* buf, int* len)
+{
+ struct mode_state ms = { buf, 0, 0, { 0, 0, 0, 0 } };
+
+ assert(MODE_LIST_CHECK(ml));
+ assert(buf);
+ assert(len);
+
+ /* Set up the full info */
+ ms.size = *len;
+
+ /* Do we have enough space for the initial set-up? */
+ if (ms.size < 4)
+ return 0;
+
+ /* OK, initialize the buffer appropriately */
+ *(ms.types[TYPE_A] = buf + 0) = ',';
+ *(ms.types[TYPE_B] = buf + 1) = ',';
+ *(ms.types[TYPE_C] = buf + 2) = ',';
+ *(ms.types[TYPE_D] = buf + 3) = '\0';
+
+ /* Current length: 3 */
+ ms.len = 3;
+
+ /* Now let's iterate over all the mode descriptors */
+ if (regtab_iter(&ml->ml_table, (regiter_t) ms_build, &ms))
+ return 0; /* some kind of failure occurred */
+
+ return ms.buf; /* return the buffer */
+}
+
+/** Convert a flag value with prefix priority into just the priority. */
+#define flag2prio(f) (((f) & MDFLAG_PRIO) >> 16)
+
+/** Current state of prefix accumulation. */
+struct pfx_state {
+ int count; /**< Number of modes to enter. */
+ int max; /**< Maximum number of modes to enter. */
+ modedesc_t* modes[flag2prio(MDFLAG_PRIO) + 1];
+ /**< Modes contributing to prefix. */
+};
+
+/** Determine if a specific mode participates in the prefix calculation.
+ * @param[in] table Registration table modedesc_t is in.
+ * @param[in] md Mode descriptor.
+ * @param[in,out] ps Prefix string state.
+ * @return 0 to continue iteration, non-zero if there is a problem.
+ */
+static int
+mp_build(regtab_t* table, modedesc_t* md, struct pfx_state *ps)
+{
+ assert(MODE_DESC_CHECK(md));
+
+ /* Does this mode have an associated prefix? */
+ if (md->md_prefix) {
+ if (ps->modes[flag2prio(md->md_flags)] || ps->count >= ps->max)
+ return -1; /* two modes of the same priority, or buffer too small */
+
+ ps->modes[flag2prio(md->md_flags)] = md; /* save it */
+ ps->count++;
+ }
+
+ return 0; /* keep iterating */
+}
+
+/** Assemble string for PREFIX component of RPL_ISUPPORT.
+ * @param[in] ml Mode list to build mode string from.
+ * @param[out] buf Buffer in which to build the string.
+ * @param[in,out] len Size of buffer; on return, length of string.
+ * @return Buffer containing prefix string.
+ */
+char*
+mode_str_prefix(modelist_t* ml, char* buf, int* len)
+{
+ struct pfx_state ps;
+ int i, j, offset;
+
+ assert(MODE_LIST_CHECK(ml));
+ assert(buf);
+ assert(len);
+
+ /* let's clear the status */
+ memset(&ps, 0, sizeof(ps));
+ ps.max = (*len - 3) / 2; /* -3 for '(', ')', and '\0' */
+
+ /* Iterate over all the mode descriptors */
+ if (regtab_iter(&ml->ml_table, (regiter_t) mp_build, &ps))
+ return 0; /* some kind of failure occurred */
+
+ /* We've now built the prefix list; set up the buffer */
+ buf[0] = '(';
+ buf[ps.count + 1] = ')';
+ offset = ps.count + 2;
+ buf[(*len = offset + ps.count)] = '\0';
+
+ /* Now fill it in */
+ for (j = 0, i = flag2prio(MDFLAG_PRIO); i >= 0; i--)
+ if (ps.modes[i]) {
+ buf[j + 1] = ps.modes[i]->md_switch;
+ buf[j + offset] = ps.modes[i]->md_prefix;
+ }
+
+ return buf; /* and return the assembled buffer */
+}
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
_______________________________________________
Patches mailing list
[email protected]
http://undernet.sbg.org/mailman/listinfo/patches