1 |
/* Routines for handling mode flags and strings. |
2 |
* |
3 |
* IRC Services is copyright (c) 1996-2009 Andrew Church. |
4 |
* E-mail: <achurch@achurch.org> |
5 |
* Parts written by Andrew Kempe and others. |
6 |
* This program is free but copyrighted software; see the file GPL.txt for |
7 |
* details. |
8 |
*/ |
9 |
|
10 |
#include "services.h" |
11 |
|
12 |
/*************************************************************************/ |
13 |
|
14 |
/* List of user/channel modes and associated mode letters. */ |
15 |
|
16 |
ModeData usermodes[] = { |
17 |
['o'] = {0x00000001}, |
18 |
['i'] = {0x00000002}, |
19 |
['w'] = {0x00000004}, |
20 |
}; |
21 |
|
22 |
ModeData chanmodes[] = { |
23 |
['i'] = {0x00000001, 0, 0}, |
24 |
['m'] = {0x00000002, 0, 0}, |
25 |
['n'] = {0x00000004, 0, 0}, |
26 |
['p'] = {0x00000008, 0, 0}, |
27 |
['s'] = {0x00000010, 0, 0}, |
28 |
['t'] = {0x00000020, 0, 0}, |
29 |
['k'] = {0x00000040, 1, 1}, |
30 |
['l'] = {0x00000080, 1, 0}, |
31 |
['b'] = {0x80000000, 1, 1, 0, MI_MULTIPLE}, |
32 |
}; |
33 |
|
34 |
ModeData chanusermodes[] = { |
35 |
['o'] = {0x00000001, 1, 1, '@'}, |
36 |
['v'] = {0x00000002, 1, 1, '+'}, |
37 |
}; |
38 |
|
39 |
/* The following are initialized by mode_setup(): */ |
40 |
int32 usermode_reg; /* Usermodes applied to registered nicks */ |
41 |
int32 chanmode_reg; /* Chanmodes applied to registered chans */ |
42 |
int32 chanmode_regonly; /* Chanmodes indicating regnick-only channels*/ |
43 |
int32 chanmode_opersonly; /* Chanmodes indicating oper-only channels */ |
44 |
char chanmode_multiple[257]; /* Chanmodes that can be set multiple times */ |
45 |
|
46 |
/* Flag tables, used internally to speed up flag lookups. 0 indicates a |
47 |
* flag with no associated mode. */ |
48 |
static char userflags[31], chanflags[31], chanuserflags[31]; |
49 |
|
50 |
/* Table of channel user mode prefixes, used like flag tables above. */ |
51 |
static int32 prefixtable[256]; |
52 |
|
53 |
/* Tables used for fast lookups. */ |
54 |
static ModeData *modetable[] = {usermodes, chanmodes, chanusermodes}; |
55 |
static char *flagtable[] = {userflags, chanflags, chanuserflags}; |
56 |
|
57 |
/*************************************************************************/ |
58 |
/*************************************************************************/ |
59 |
|
60 |
/* Initialize flag tables and flag sets from mode tables. Must be called |
61 |
* before any other mode_* function, and should be called again if the mode |
62 |
* tables are modified. |
63 |
*/ |
64 |
|
65 |
void mode_setup(void) |
66 |
{ |
67 |
int i; |
68 |
ModeData *modelist; |
69 |
char *flaglist; |
70 |
int multi_index = 0; /* index into chanmode_multiple[] */ |
71 |
|
72 |
modelist = usermodes; |
73 |
flaglist = userflags; |
74 |
for (i = 0; i < 256; i++) { |
75 |
if (modelist[i].flag) { |
76 |
int n = 0; |
77 |
uint32 tmp = (uint32) modelist[i].flag; |
78 |
if (modelist[i].info & MI_REGISTERED) |
79 |
usermode_reg |= tmp; |
80 |
while (tmp >>= 1) |
81 |
n++; |
82 |
if (n < 31) |
83 |
flaglist[n] = (char)i; |
84 |
} |
85 |
} |
86 |
|
87 |
modelist = chanmodes; |
88 |
flaglist = chanflags; |
89 |
for (i = 0; i < 256; i++) { |
90 |
if (modelist[i].flag) { |
91 |
int n = 0; |
92 |
uint32 tmp = (uint32) modelist[i].flag; |
93 |
if (modelist[i].info & MI_REGISTERED) |
94 |
chanmode_reg |= tmp; |
95 |
if (modelist[i].info & MI_REGNICKS_ONLY) |
96 |
chanmode_regonly |= tmp; |
97 |
if (modelist[i].info & MI_OPERS_ONLY) |
98 |
chanmode_opersonly |= tmp; |
99 |
if (modelist[i].info & MI_MULTIPLE) |
100 |
chanmode_multiple[multi_index++] = i; |
101 |
while (tmp >>= 1) |
102 |
n++; |
103 |
if (n < 31) |
104 |
flaglist[n] = (char)i; |
105 |
} |
106 |
} |
107 |
chanmode_multiple[multi_index] = 0; |
108 |
|
109 |
modelist = chanusermodes; |
110 |
flaglist = chanuserflags; |
111 |
for (i = 0; i < 256; i++) { |
112 |
if (modelist[i].flag) { |
113 |
int n = 0; |
114 |
uint32 tmp = (uint32) modelist[i].flag; |
115 |
prefixtable[ (uint8)modelist[i].prefix ] = tmp; |
116 |
while (tmp >>= 1) |
117 |
n++; |
118 |
if (n < 31) |
119 |
flaglist[n] = (char)i; |
120 |
if (modelist[i].plus_params!=1 || modelist[i].minus_params!=1) { |
121 |
log("modes: Warning: channel user mode `%c' takes %d/%d" |
122 |
" parameters (should be 1/1)", |
123 |
i, modelist[i].plus_params, modelist[i].minus_params); |
124 |
} |
125 |
} |
126 |
} |
127 |
} |
128 |
|
129 |
/*************************************************************************/ |
130 |
|
131 |
/* Return the flag corresponding to the given mode character, or 0 if no |
132 |
* such mode exists. Return MODE_INVALID if the mode exists but has no |
133 |
* assigned flag. `which' indicates the mode set to be used: MODE_USER, |
134 |
* MODE_CHANNEL, or MODE_CHANUSER. |
135 |
*/ |
136 |
|
137 |
int32 mode_char_to_flag(char c, int which) |
138 |
{ |
139 |
if (which != MODE_USER && which != MODE_CHANNEL && which != MODE_CHANUSER){ |
140 |
log("mode_char_to_flag(): bad `which' value %d", which); |
141 |
return MODE_INVALID; |
142 |
} |
143 |
return modetable[which][(uint8)c].flag; |
144 |
} |
145 |
|
146 |
/*************************************************************************/ |
147 |
|
148 |
/* Return the number of parameters the given mode takes, as |
149 |
* (plus_params<<8) | (minus_params). Return -1 if there is no such mode. |
150 |
*/ |
151 |
|
152 |
int mode_char_to_params(char c, int which) |
153 |
{ |
154 |
ModeData *ptr; |
155 |
|
156 |
if (which != MODE_USER && which != MODE_CHANNEL && which != MODE_CHANUSER){ |
157 |
log("mode_char_to_params(): bad `which' value %d", which); |
158 |
return -1; |
159 |
} |
160 |
ptr = &modetable[which][(uint8)c]; |
161 |
return ptr->plus_params<<8 | ptr->minus_params; |
162 |
} |
163 |
|
164 |
/*************************************************************************/ |
165 |
|
166 |
/* Return the mode character corresponding to the given flag, or 0 if no |
167 |
* such mode exists. If more than one bit is set in `f', then the mode |
168 |
* character corresponding to the highest bit is used. |
169 |
*/ |
170 |
|
171 |
char mode_flag_to_char(int32 f, int which) |
172 |
{ |
173 |
char *flaglist; |
174 |
int n = 0, tmp = f; |
175 |
|
176 |
if (which != MODE_USER && which != MODE_CHANNEL && which != MODE_CHANUSER){ |
177 |
log("mode_flag_to_char(): bad `which' value %d", which); |
178 |
return 0; |
179 |
} |
180 |
flaglist = flagtable[which]; |
181 |
|
182 |
while (tmp >>= 1) |
183 |
n++; |
184 |
if (n >= 31) |
185 |
return 0; |
186 |
return flaglist[n]; |
187 |
} |
188 |
|
189 |
/*************************************************************************/ |
190 |
|
191 |
/* Return the flag set corresponding to the given string of mode characters |
192 |
* in the given mode set. If MODE_NOERROR is set in `which', invalid mode |
193 |
* characters are ignored; if not set, (CMODE_INVALID | modechar) is |
194 |
* returned for the first invalid mode character found. |
195 |
*/ |
196 |
|
197 |
int32 mode_string_to_flags(const char *s, int which) |
198 |
{ |
199 |
int noerror = (which & MODE_NOERROR); |
200 |
int32 flags = 0; |
201 |
const ModeData *modelist; |
202 |
|
203 |
which &= ~MODE_NOERROR; |
204 |
if (which != MODE_USER && which != MODE_CHANNEL && which != MODE_CHANUSER){ |
205 |
log("mode_string_to_flags(): bad `which' value %d", which|noerror); |
206 |
return 0; |
207 |
} |
208 |
modelist = modetable[which]; |
209 |
|
210 |
while (*s) { |
211 |
int f = modelist[(uint8)*s].flag; |
212 |
if (!f) { |
213 |
if (noerror) { |
214 |
s++; |
215 |
continue; |
216 |
} |
217 |
return MODE_INVALID | *s; |
218 |
} |
219 |
if (f != MODE_INVALID) |
220 |
flags |= f; |
221 |
s++; |
222 |
} |
223 |
return flags; |
224 |
} |
225 |
|
226 |
/*************************************************************************/ |
227 |
|
228 |
/* Return the string of mode characters corresponding to the given flag |
229 |
* set. If the flag set has invalid flags in it, they are ignored. |
230 |
* The returned string is stored in a static buffer which will be |
231 |
* overwritten on the next call. |
232 |
*/ |
233 |
|
234 |
char *mode_flags_to_string(int32 flags, int which) |
235 |
{ |
236 |
static char buf[32]; |
237 |
char *s = buf; |
238 |
int n = 0; |
239 |
const char *flaglist; |
240 |
|
241 |
if (which != MODE_USER && which != MODE_CHANNEL && which != MODE_CHANUSER){ |
242 |
log("mode_flags_to_string(): bad `which' value %d", which); |
243 |
*buf = 0; |
244 |
return buf; |
245 |
} |
246 |
flaglist = flagtable[which]; |
247 |
|
248 |
flags &= ~MODE_INVALID; |
249 |
while (flags) { |
250 |
if ((flags & 1) && flaglist[n]) |
251 |
*s++ = flaglist[n]; |
252 |
n++; |
253 |
flags >>= 1; |
254 |
} |
255 |
*s = 0; |
256 |
return buf; |
257 |
} |
258 |
|
259 |
/*************************************************************************/ |
260 |
|
261 |
/* Return the flag corresponding to the given channel user mode prefix, or |
262 |
* 0 if no such mode exists. |
263 |
*/ |
264 |
|
265 |
int32 cumode_prefix_to_flag(char c) |
266 |
{ |
267 |
return prefixtable[(uint8)c]; |
268 |
} |
269 |
|
270 |
/*************************************************************************/ |
271 |
|
272 |
/* |
273 |
* Local variables: |
274 |
* c-file-style: "stroustrup" |
275 |
* c-file-offsets: ((case-label . *) (statement-case-intro . *)) |
276 |
* indent-tabs-mode: nil |
277 |
* End: |
278 |
* |
279 |
* vim: expandtab shiftwidth=4: |
280 |
*/ |