/* Routines for handling mode flags and strings.
*
* IRC Services is copyright (c) 1996-2007 Andrew Church.
* E-mail: <achurch@achurch.org>
* Parts written by Andrew Kempe and others.
* This program is free but copyrighted software; see the file COPYING for
* details.
*/
#include "services.h"
/*************************************************************************/
/* List of user/channel modes and associated mode letters. */
ModeData usermodes[] = {
['o'] = {0x00000001},
['i'] = {0x00000002},
['w'] = {0x00000004},
};
ModeData chanmodes[] = {
['i'] = {0x00000001, 0, 0},
['m'] = {0x00000002, 0, 0},
['n'] = {0x00000004, 0, 0},
['p'] = {0x00000008, 0, 0},
['s'] = {0x00000010, 0, 0},
['t'] = {0x00000020, 0, 0},
['k'] = {0x00000040, 1, 1},
['l'] = {0x00000080, 1, 0},
['b'] = {0x80000000, 1, 1, 0, MI_MULTIPLE},
};
ModeData chanusermodes[] = {
['o'] = {0x00000001, 1, 1, '@'},
['v'] = {0x00000002, 1, 1, '+'},
};
/* The following are initialized by mode_setup(): */
int32 usermode_reg; /* Usermodes applied to registered nicks */
int32 chanmode_reg; /* Chanmodes applied to registered chans */
int32 chanmode_regonly; /* Chanmodes indicating regnick-only channels*/
int32 chanmode_opersonly; /* Chanmodes indicating oper-only channels */
int32 chanusermode_owner; /* Chanuser-modes applied to channel owner */
char chanmode_multiple[257]; /* Chanmodes that can be set multiple times */
/* Flag tables, used internally to speed up flag lookups. 0 indicates a
* flag with no associated mode. */
static char userflags[31], chanflags[31], chanuserflags[31];
/* Table of channel user mode prefixes, used like flag tables above. */
static int32 prefixtable[256];
/* Tables used for fast lookups. */
static ModeData *modetable[] = {usermodes, chanmodes, chanusermodes};
static char *flagtable[] = {userflags, chanflags, chanuserflags};
/*************************************************************************/
/*************************************************************************/
/* Initialize flag tables and flag sets from mode tables. Must be called
* before any other mode_* function, and should be called again if the mode
* tables are modified.
*/
void mode_setup(void)
{
int i;
ModeData *modelist;
char *flaglist;
int multi_index = 0; /* index into chanmode_multiple[] */
modelist = usermodes;
flaglist = userflags;
for (i = 0; i < 256; i++) {
if (modelist[i].flag) {
int n = 0;
uint32 tmp = (uint32) modelist[i].flag;
if (modelist[i].info & MI_REGISTERED)
usermode_reg |= tmp;
while (tmp >>= 1)
n++;
if (n < 31)
flaglist[n] = (char)i;
}
}
modelist = chanmodes;
flaglist = chanflags;
for (i = 0; i < 256; i++) {
if (modelist[i].flag) {
int n = 0;
uint32 tmp = (uint32) modelist[i].flag;
if (modelist[i].info & MI_REGISTERED)
chanmode_reg |= tmp;
if (modelist[i].info & MI_REGNICKS_ONLY)
chanmode_regonly |= tmp;
if (modelist[i].info & MI_OPERS_ONLY)
chanmode_opersonly |= tmp;
if (modelist[i].info & MI_MULTIPLE)
chanmode_multiple[multi_index++] = i;
while (tmp >>= 1)
n++;
if (n < 31)
flaglist[n] = (char)i;
}
}
chanmode_multiple[multi_index] = 0;
modelist = chanusermodes;
flaglist = chanuserflags;
for (i = 0; i < 256; i++) {
if (modelist[i].flag) {
int n = 0;
uint32 tmp = (uint32) modelist[i].flag;
prefixtable[ (uint8)modelist[i].prefix ] = tmp;
if (modelist[i].info & MI_CHANOWNER)
chanusermode_owner |= tmp;
while (tmp >>= 1)
n++;
if (n < 31)
flaglist[n] = (char)i;
if (modelist[i].plus_params!=1 || modelist[i].minus_params!=1) {
log("modes: Warning: channel user mode `%c' takes %d/%d"
" parameters (should be 1/1)",
i, modelist[i].plus_params, modelist[i].minus_params);
}
}
}
}
/*************************************************************************/
/* Return the flag corresponding to the given mode character, or 0 if no
* such mode exists. Return MODE_INVALID if the mode exists but has no
* assigned flag. `which' indicates the mode set to be used: MODE_USER,
* MODE_CHANNEL, or MODE_CHANUSER.
*/
int32 mode_char_to_flag(char c, int which)
{
return modetable[which][(uint8)c].flag;
}
/*************************************************************************/
/* Return the number of parameters the given mode takes, as
* (plus_params<<8) | (minus_params). Return -1 if there is no such mode.
*/
int mode_char_to_params(char c, int which)
{
ModeData *ptr = &modetable[which][(uint8)c];
return ptr->plus_params<<8 | ptr->minus_params;
}
/*************************************************************************/
/* Return the mode character corresponding to the given flag, or 0 if no
* such mode exists. If more than one bit is set in `f', then the mode
* character corresponding to the highest bit is used.
*/
char mode_flag_to_char(int32 f, int which)
{
char *flaglist = flagtable[which];
int n = 0, tmp = f;
while (tmp >>= 1)
n++;
if (n >= 31)
return 0;
return flaglist[n];
}
/*************************************************************************/
/* Return the flag set corresponding to the given string of mode characters
* in the given mode set. If MODE_NOERROR is set in `which', invalid mode
* characters are ignored; if not set, (CMODE_INVALID | modechar) is
* returned for the first invalid mode character found.
*/
int32 mode_string_to_flags(const char *s, int which)
{
int32 flags = 0;
const ModeData *modelist = modetable[which & ~MODE_NOERROR];
while (*s) {
int f = modelist[(uint8)*s].flag;
if (!f) {
if (which & MODE_NOERROR) {
s++;
continue;
}
return MODE_INVALID | *s;
}
if (f != MODE_INVALID)
flags |= f;
s++;
}
return flags;
}
/*************************************************************************/
/* Return the string of mode characters corresponding to the given flag
* set. If the flag set has invalid flags in it, they are ignored.
* The returned string is stored in a static buffer which will be
* overwritten on the next call.
*/
char *mode_flags_to_string(int32 flags, int which)
{
static char buf[32];
char *s = buf;
int n = 0;
const char *flaglist = flagtable[which];
flags &= ~MODE_INVALID;
while (flags) {
if ((flags & 1) && flaglist[n])
*s++ = flaglist[n];
n++;
flags >>= 1;
}
*s = 0;
return buf;
}
/*************************************************************************/
/* Return the flag corresponding to the given channel user mode prefix, or
* 0 if no such mode exists.
*/
int32 cumode_prefix_to_flag(char c)
{
return prefixtable[(uint8)c];
}
/*************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1