]>
Commit | Line | Data |
---|---|---|
c86edd1d Q |
1 | |
2 | #include <stdlib.h> | |
3 | #include <assert.h> | |
135d6084 | 4 | #include <string.h> |
5 | #include <ctype.h> | |
c86edd1d | 6 | |
c86edd1d Q |
7 | #include "hchannel.h" |
8 | #include "haccount.h" | |
9 | #include "helpmod.h" | |
10 | #include "hqueue.h" | |
11 | #include "hgen.h" | |
12 | #include "hchanban.h" | |
13 | #include "hban.h" | |
14 | ||
15 | hchannel *hchannel_add(const char *cname) | |
16 | { | |
17 | channel *cp; | |
18 | hchannel *hchan; | |
19 | ||
20 | cp = findchannel((char*)cname); | |
21 | if (!cp) | |
22 | { | |
23 | localcreatechannel(helpmodnick, (char*)cname); | |
24 | cp = findchannel((char*)cname); | |
25 | } | |
26 | else | |
27 | { | |
28 | localjoinchannel(helpmodnick, cp); | |
29 | localgetops(helpmodnick, cp); | |
30 | } | |
31 | ||
32 | hchan = (hchannel*)malloc(sizeof(hchannel)); | |
33 | ||
34 | hchan->welcome[0] = '\0'; | |
35 | hchan->real_channel = cp; | |
36 | hchan->flags = H_CHANFLAGS_DEFAULT; | |
37 | hchan->channel_users = NULL; | |
38 | hchan->channel_hterms = NULL; | |
39 | hchan->max_idle = 5 * HDEF_m; | |
40 | hchan->topic = NULL; | |
41 | hchan->report_to = NULL; | |
42 | ||
43 | hchan->autoqueue = 0; | |
44 | hchan->jf_control = time(NULL); | |
45 | hchan->lc_profile = NULL; | |
46 | hchan->censor = NULL; | |
47 | ||
48 | hchan->htickets = NULL; | |
9af95c3d | 49 | hchan->ticket_message = NULL; |
c86edd1d | 50 | |
3a839281 | 51 | hchan->last_activity = time(NULL); |
52 | hchan->last_staff_activity = time(NULL); | |
c86edd1d Q |
53 | hchan->stats = get_hstat_channel(); |
54 | ||
55 | hchan->next = hchannels; | |
56 | hchannels = hchan; | |
57 | ||
58 | { | |
59 | int i; | |
60 | nick *nck; | |
61 | huser *husr; | |
62 | huser_channel *tmp; | |
63 | for (i=0;i < hchan->real_channel->users->hashsize;i++) | |
64 | { | |
65 | nck = getnickbynumeric(hchan->real_channel->users->content[i]); | |
66 | if (!nck) /* it's a hash, not an array */ | |
67 | continue; | |
68 | ||
69 | if ((husr = huser_get(nck)) == NULL) | |
70 | husr = huser_add(nck); | |
3a839281 | 71 | |
72 | tmp = huser_add_channel(husr, hchan); | |
c86edd1d Q |
73 | hchannel_add_user(hchan, husr); |
74 | ||
75 | if (hchan->real_channel->users->content[i] & CUMODE_OP) | |
76 | tmp->flags |= HCUMODE_OP; | |
77 | if (hchan->real_channel->users->content[i] & CUMODE_VOICE) | |
78 | tmp->flags |= HCUMODE_VOICE; | |
79 | } | |
80 | } | |
81 | return hchan; | |
82 | } | |
83 | ||
84 | int hchannel_del(hchannel *hchan) | |
85 | { | |
86 | hchannel *tmp, **ptr = &hchannels; | |
87 | ||
88 | for (;*ptr;ptr = &(*ptr)->next) | |
89 | if (*ptr == hchan) | |
90 | break; | |
91 | ||
92 | assert(*ptr != NULL); | |
93 | ||
94 | tmp = hchan->next; | |
95 | ||
96 | hcensor_del_all(&(hchan->censor)); | |
97 | hterm_del_all(&hchan->channel_hterms); | |
98 | htopic_del_all(&hchan->topic); | |
99 | hstat_del_channel(hchan); | |
100 | free(hchan->stats); | |
101 | ||
102 | while (hchan->htickets) | |
103 | hticket_del(hchan->htickets, hchan); | |
104 | ||
334b567e | 105 | localpartchannel(helpmodnick, hchan->real_channel, "Channel Removed"); |
c86edd1d Q |
106 | |
107 | free(hchan); | |
108 | ||
109 | *ptr = tmp; | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
114 | int hchannel_authority(hchannel *hchan, struct huser_struct *husr) | |
115 | { | |
116 | if ((hchan->flags & H_OPER_ONLY) && (huser_get_level(husr) < H_OPER)) | |
117 | return 0; | |
118 | return 1; | |
119 | } | |
120 | ||
121 | hchannel *hchannel_get_by_name(const char *cname) | |
122 | { | |
123 | hchannel *tmp = hchannels; | |
124 | for (;tmp;tmp=tmp->next) | |
125 | if (!ircd_strcmp(cname, tmp->real_channel->index->name->content)) | |
126 | return tmp; | |
127 | return NULL; | |
128 | } | |
129 | ||
130 | hchannel *hchannel_get_by_channel(channel *chan) | |
131 | { | |
132 | hchannel *tmp; | |
133 | ||
134 | if (chan == NULL) | |
135 | return NULL; | |
136 | ||
137 | tmp = hchannels; | |
138 | for (;tmp;tmp=tmp->next) | |
139 | if (tmp->real_channel == chan) | |
140 | return tmp; | |
141 | return NULL; | |
142 | } | |
143 | ||
c86edd1d Q |
144 | const char *hchannel_get_name(hchannel *hchan) |
145 | { | |
146 | return hchan->real_channel->index->name->content; | |
147 | } | |
148 | ||
149 | void hchannel_del_all(void) | |
150 | { | |
151 | while (hchannels) | |
152 | hchannel_del(hchannels); | |
153 | } | |
154 | ||
155 | hchannel_user *hchannel_on_channel(hchannel *hchan, struct huser_struct *husr) | |
156 | { | |
157 | hchannel_user *ptr = hchan->channel_users; | |
158 | for (;ptr;ptr = ptr->next) | |
159 | if (ptr->husr == husr) | |
160 | return ptr; | |
161 | return NULL; | |
162 | } | |
163 | ||
164 | hchannel_user *hchannel_add_user(hchannel *hchan, struct huser_struct *husr) | |
165 | { | |
166 | hchannel_user **tmp = &(hchan->channel_users); | |
167 | assert(hchannel_on_channel(hchan, husr) == NULL); | |
168 | ||
169 | for (;*tmp;tmp = &(*tmp)->next); | |
170 | ||
171 | *tmp = (hchannel_user*)malloc(sizeof(hchannel_user)); | |
172 | (*tmp)->husr = husr; | |
173 | (*tmp)->time_joined = time(NULL); | |
174 | (*tmp)->next = NULL; | |
175 | ||
176 | assert(hchannel_on_channel(hchan, husr) != NULL); | |
177 | ||
178 | return *tmp; | |
179 | } | |
180 | ||
181 | hchannel_user *hchannel_del_user(hchannel *hchan, struct huser_struct *husr) | |
182 | { | |
183 | hchannel_user **tmp = &(hchan->channel_users); | |
184 | assert(hchannel_on_channel(hchan, husr) != NULL); | |
185 | ||
186 | for (;*tmp;tmp = &(*tmp)->next) | |
187 | if ((*tmp)->husr == husr) | |
188 | { | |
189 | hchannel_user *ptr = (*tmp)->next; | |
190 | free(*tmp); | |
191 | *tmp = ptr; | |
192 | ||
193 | assert(hchannel_on_channel(hchan, husr) == NULL); | |
194 | return NULL; | |
195 | } | |
196 | return NULL; | |
197 | } | |
198 | ||
199 | void hchannel_remove_inactive_users(void) | |
200 | { | |
201 | hchannel *hchan = hchannels; | |
202 | ||
203 | for (;hchan;hchan = hchan->next) | |
204 | { | |
205 | if (hchan->flags & H_ANTI_IDLE && !(hchan->flags & H_PASSIVE)) | |
206 | { | |
207 | hchannel_user **hchanuser = &hchan->channel_users; | |
208 | while (*hchanuser) | |
209 | { | |
ce659137 | 210 | if ( |
211 | (huser_get_level((*hchanuser)->husr) == H_PEON) && | |
212 | (time(NULL) - huser_on_channel((*hchanuser)->husr,hchan)->last_activity >= hchan->max_idle) && | |
213 | !(on_queue((*hchanuser)->husr, huser_on_channel((*hchanuser)->husr, hchan))) && | |
214 | !IsSetHost((*hchanuser)->husr->real_user) | |
215 | ) | |
216 | { | |
217 | if (huser_on_channel((*hchanuser)->husr, hchan)->flags & H_IDLE_WARNING) | |
c86edd1d | 218 | { |
b808acb7 | 219 | const char *banmask = hban_ban_string((*hchanuser)->husr->real_user, HBAN_HOST); |
f1cc5921 CP |
220 | int bantime = 10; |
221 | helpmod_setban(hchan, banmask, time(NULL) + bantime * HDEF_m, MCB_ADD, HLAZY); | |
c86edd1d | 222 | |
f1cc5921 | 223 | helpmod_kick(hchan, (*hchanuser)->husr, "Please do not idle in %s (%dmin anti-idle tempban). If you still require assistance, please try again later.", hchannel_get_name(hchan), bantime); |
c86edd1d Q |
224 | continue; |
225 | } | |
226 | else | |
227 | { | |
228 | helpmod_reply((*hchanuser)->husr, NULL, "You are currently idle in %s. Please part the channel if you have nothing to do there", hchannel_get_name(hchan)); | |
229 | huser_on_channel((*hchanuser)->husr, hchan)->flags |= H_IDLE_WARNING; | |
9af95c3d | 230 | } |
231 | } | |
9f824c95 | 232 | /*hcommit_modes();*/ |
c86edd1d | 233 | hchanuser = &(*hchanuser)->next; |
9f824c95 | 234 | } |
235 | hcommit_modes(); | |
c86edd1d Q |
236 | } |
237 | /* Additionally, test if the channel has queue but no idle opers / staff */ | |
238 | if (hchan->flags & H_QUEUE && hchan->flags & H_QUEUE_TIMEOUT) | |
239 | { | |
240 | hchannel_user *tmp; | |
241 | for (tmp = hchan->channel_users;tmp;tmp = tmp->next) | |
052247fa | 242 | if (huser_get_level(tmp->husr) >= H_TRIAL) |
c86edd1d Q |
243 | { |
244 | huser_channel *huserchan = huser_on_channel(tmp->husr, hchan); | |
245 | if ((time(NULL) - huserchan->last_activity < HELPMOD_QUEUE_TIMEOUT) && (huserchan->last_activity != tmp->time_joined)) | |
246 | break; | |
247 | } | |
248 | if (!tmp) | |
249 | { | |
250 | hchan->flags &= ~H_QUEUE; | |
251 | if (hchan->flags & H_REPORT && hchannel_is_valid(hchan->report_to)) | |
252 | helpmod_message_channel(hchan->report_to, "%s: Channel queue deactivated because of inactivity", hchannel_get_name(hchan)); | |
253 | hchannel_conf_change(hchan, hchan->flags | H_QUEUE); | |
254 | } | |
255 | } | |
256 | } | |
257 | } | |
258 | ||
259 | void hchannel_report(void) | |
260 | { | |
261 | hchannel *hchan = hchannels; | |
262 | for (;hchan;hchan = hchan->next) | |
263 | if (hchan->flags & H_REPORT && !(hchan->flags & H_PASSIVE) && hchannel_is_valid(hchan->report_to)) | |
264 | { | |
265 | int total = hchannel_count_users(hchan, H_ANY); | |
266 | int peons = hchannel_count_users(hchan, H_PEON); | |
267 | int services = hchannel_count_users(hchan, H_SERVICE); | |
268 | ||
269 | if (peons == 0) | |
270 | return; | |
271 | ||
272 | if (hchan->flags & H_QUEUE) | |
273 | { | |
274 | int peons_queue = hchannel_count_queue(hchan); | |
275 | helpmod_message_channel(hchan->report_to, "%s: %d user%s in queue and %d user%s currently receiving support. %d Non-user%s. Average queue time %s", hchannel_get_name(hchan), peons_queue, (peons_queue==1)?"":"s", peons - peons_queue, (peons - peons_queue == 1)?"":"s", total-peons-services, (total-peons-services == 1)?"":"s", helpmod_strtime(hqueue_average_time(hchan))); | |
276 | } | |
277 | else | |
278 | helpmod_message_channel(hchan->report_to, "%s: %d user%s and %d non-user%s", hchannel_get_name(hchan), peons, (peons == 1)?"":"s", total-peons-services, (total-peons-services == 1)?"":"s"); | |
279 | } | |
280 | } | |
281 | ||
282 | void hchannel_set_topic(hchannel *hchan) | |
283 | { | |
284 | if (hchan->flags & H_HANDLE_TOPIC) | |
285 | helpmod_set_topic(hchan, htopic_construct(hchan->topic)); | |
286 | } | |
287 | ||
288 | void hchannels_match_accounts(void) | |
289 | { | |
290 | hchannel *hchan = hchannels; | |
291 | hchannel_user *hchanuser; | |
292 | for (;hchan;hchan = hchan->next) | |
293 | for (hchanuser = hchan->channel_users;hchanuser;hchanuser = hchanuser->next) | |
294 | if (hchanuser->husr->account == NULL && IsAccount(hchanuser->husr->real_user)) | |
3a839281 | 295 | hchanuser->husr->account = haccount_get_by_name(huser_get_auth(hchanuser->husr)); |
c86edd1d Q |
296 | } |
297 | ||
298 | int hchannels_on_queue(huser *husr) | |
299 | { | |
300 | huser_channel *huserchan = husr->hchannels; | |
301 | for (;huserchan;huserchan = huserchan->next) | |
302 | if (on_queue(husr, huserchan)) | |
303 | return 1; | |
304 | return 0; | |
305 | } | |
306 | ||
307 | int hchannels_on_desk(struct huser_struct* husr) | |
308 | { | |
309 | huser_channel *huserchan = husr->hchannels; | |
310 | for (;huserchan;huserchan = huserchan->next) | |
311 | if (on_desk(husr, huserchan)) | |
312 | return 1; | |
313 | return 0; | |
314 | } | |
315 | ||
316 | void hchannels_dnmo(struct huser_struct *husr) | |
317 | { | |
318 | hchannel *hchan = hchannels; | |
319 | for (;hchan;hchan = hchan->next) | |
320 | { | |
321 | huser_channel *huserchan = huser_on_channel(husr, hchan); | |
322 | /*if (on_queue(husr, huserchan) || on_desk(husr, huserchan))*/ | |
323 | if (huserchan != NULL) | |
324 | { | |
f011b15a | 325 | hchannel_user *tmp = NULL, **hchanuser = &hchan->channel_users; |
c86edd1d Q |
326 | for (;*hchanuser;hchanuser = &(*hchanuser)->next) |
327 | if ((*hchanuser)->husr == husr) | |
328 | { | |
329 | tmp = *hchanuser; | |
330 | *hchanuser = (*hchanuser)->next; | |
331 | if (!*hchanuser) | |
332 | break; | |
333 | } | |
334 | *hchanuser = tmp; | |
7d54716c | 335 | assert(*hchanuser != NULL); |
c86edd1d Q |
336 | (*hchanuser)->next = NULL; |
337 | if (on_desk(husr, huserchan)) | |
338 | { | |
339 | helpmod_channick_modes(husr, hchan, MC_DEVOICE, HLAZY); | |
340 | huserchan->flags &= ~HQUEUE_DONE; | |
341 | } | |
342 | } | |
343 | } | |
344 | } | |
345 | ||
346 | int hchannel_count_users(hchannel *hchan, hlevel lvl) | |
347 | { | |
348 | int count = 0; | |
349 | hchannel_user *hchanuser = hchan->channel_users; | |
350 | for (;hchanuser;hchanuser = hchanuser->next) | |
351 | if (lvl == H_ANY) | |
352 | count++; | |
353 | else if (huser_get_level(hchanuser->husr) == lvl) | |
354 | count++; | |
355 | return count; | |
356 | } | |
357 | ||
358 | int hchannel_count_queue(hchannel *hchan) | |
359 | { | |
360 | int count = 0; | |
361 | hchannel_user *hchanuser = hchan->channel_users; | |
362 | for (;hchanuser;hchanuser = hchanuser->next) | |
363 | { | |
364 | if (on_queue(hchanuser->husr, huser_on_channel(hchanuser->husr, hchan))) | |
365 | count++; | |
366 | } | |
367 | return count; | |
368 | } | |
369 | ||
370 | int hchannel_is_valid(hchannel *hchan) | |
371 | { | |
372 | hchannel *ptr = hchannels; | |
373 | for (;ptr;ptr = ptr->next) | |
374 | if (hchan == ptr) | |
375 | return 1; | |
376 | return 0; | |
377 | } | |
378 | ||
379 | void hchannel_mode_check(hchannel *hchan) | |
380 | { | |
381 | if (((hchan->flags & H_MAINTAIN_M) || (hchan->flags & H_QUEUE)) && !IsModerated(hchan->real_channel)) | |
382 | helpmod_simple_modes(hchan, CHANMODE_MODERATE, 0,0); | |
383 | else if (!((hchan->flags & H_MAINTAIN_M) || (hchan->flags & H_QUEUE)) && IsModerated(hchan->real_channel)) | |
384 | helpmod_simple_modes(hchan, 0, CHANMODE_MODERATE ,0); | |
385 | if (hchan->flags & H_MAINTAIN_I && !IsInviteOnly(hchan->real_channel)) | |
386 | helpmod_simple_modes(hchan, CHANMODE_INVITEONLY, 0,0); | |
387 | else if (!(hchan->flags & H_MAINTAIN_I) && IsInviteOnly(hchan->real_channel)) | |
388 | helpmod_simple_modes(hchan, 0, CHANMODE_INVITEONLY, 0); | |
389 | } | |
390 | ||
391 | void hchannel_conf_change(hchannel *hchan, int old_flags) | |
392 | { | |
393 | int i; | |
394 | hflagchange change; | |
395 | ||
396 | for (i=0;i<HCHANNEL_CONF_COUNT;i++) | |
397 | { | |
398 | if ((hchan->flags ^ old_flags) & (1 << i)) | |
399 | { | |
400 | change = (hchan->flags & (1 << i))?H_ON:H_OFF; | |
401 | switch (1 << i) | |
402 | { | |
403 | case H_QUEUE: | |
404 | hchannel_mode_check(hchan); | |
405 | if (change == H_ON) | |
406 | helpmod_message_channel(hchan, "Channel queue has been activated, all users enqueued"); | |
407 | else | |
408 | helpmod_message_channel(hchan, "Channel queue has been deactivated"); | |
409 | break; | |
410 | case H_MAINTAIN_I: | |
411 | case H_MAINTAIN_M: | |
412 | hchannel_mode_check(hchan); | |
413 | break; | |
414 | } | |
415 | } | |
416 | } | |
417 | } | |
418 | ||
419 | int hchannel_count(void) | |
420 | { | |
421 | hchannel *hchan = hchannels; | |
422 | int count = 0; | |
423 | for (;hchan;hchan = hchan->next) | |
424 | count++; | |
425 | return count; | |
426 | } | |
427 | ||
428 | void hchannel_activate_join_flood(hchannel *hchan) | |
429 | { | |
430 | hchannel_user **hchanuser = &hchan->channel_users; | |
431 | helpmod_simple_modes(hchan, CHANMODE_REGONLY, 0, 1); | |
432 | ||
433 | /* clean the channel of the already joined clients */ | |
434 | while (*hchanuser) | |
435 | if (((*hchanuser)->time_joined > (time(NULL) - 5)) && huser_get_level((*hchanuser)->husr) < H_STAFF) | |
436 | helpmod_kick(hchan, (*hchanuser)->husr, "Join flood"); | |
437 | else | |
438 | hchanuser = &(*hchanuser)->next; | |
439 | ||
440 | hchan->flags |= H_JOIN_FLOOD; | |
441 | ||
442 | scheduleoneshot(time(NULL) + 60, &hchannel_deactivate_join_flood, NULL); | |
443 | } | |
e908ecfa | 444 | |
c86edd1d Q |
445 | /* goes to schedule */ |
446 | void hchannel_deactivate_join_flood() | |
447 | { | |
448 | hchannel *hchan = hchannels; | |
449 | for (;hchan;hchan = hchan->next) | |
450 | if (hchan->flags & H_JOIN_FLOOD) | |
451 | { | |
452 | helpmod_simple_modes(hchan, 0, CHANMODE_REGONLY, 1); | |
453 | hchan->flags &= ~H_JOIN_FLOOD; | |
454 | } | |
c86edd1d Q |
455 | } |
456 | ||
3a839281 | 457 | const char *hchannel_get_state(hchannel* hchan, int mask) |
458 | { | |
459 | if (hchan->flags & mask) | |
460 | return "Yes"; | |
461 | else | |
462 | return "No"; | |
463 | } | |
464 | ||
135d6084 | 465 | int hchannel_highlight_detection(hchannel *hchan, const char *message) |
466 | { | |
467 | char buffer[512], *buffer_ptr = buffer, *ptr = buffer; | |
052247fa | 468 | int i, matches = 0; |
135d6084 | 469 | |
470 | strcpy(buffer, message); | |
471 | ||
052247fa CP |
472 | /* remove commas */ |
473 | for (i=0;i<512 && buffer[i] != '\0';i++) | |
474 | if (buffer[i] == ',') | |
475 | buffer[i] = ' '; | |
476 | ||
477 | /* reset i for loop */ | |
478 | i = 0; | |
135d6084 | 479 | do |
480 | { | |
481 | nick *tmp; | |
482 | huser *tmp_huser; | |
483 | huser_channel *tmp_huserchan; | |
484 | ||
485 | if (i++ > 6) | |
486 | break; | |
487 | ||
9f824c95 | 488 | while (*buffer_ptr && isspace(*buffer_ptr)) |
135d6084 | 489 | buffer_ptr++; |
490 | ||
9f824c95 | 491 | if (*buffer_ptr == '@') |
492 | buffer_ptr++; | |
493 | ||
135d6084 | 494 | if (*buffer_ptr) |
495 | { | |
496 | ptr = strchr(buffer_ptr, ' '); | |
497 | if (ptr) | |
498 | { | |
499 | *ptr = '\0'; | |
500 | ptr++; | |
501 | } | |
502 | if ((tmp = getnickbynick(buffer_ptr))) | |
503 | if ((tmp_huser = huser_get(tmp))) | |
504 | if ((tmp_huserchan = huser_on_channel(tmp_huser, hchan))) | |
505 | if ((tmp_huserchan->flags & HCUMODE_OP) && strlen(huser_get_nick(tmp_huser)) > 1) | |
506 | matches++; | |
507 | } | |
508 | if (ptr == NULL) | |
509 | break; | |
510 | else | |
511 | buffer_ptr = ptr; | |
512 | } while (*ptr); | |
513 | ||
514 | if (matches > 2) | |
515 | return 1; | |
516 | else | |
517 | return 0; | |
518 | } | |
3a839281 | 519 | |
c86edd1d Q |
520 | const char *hchannel_get_sname(int flag) |
521 | { | |
522 | if (flag < 0 || flag > HCHANNEL_CONF_COUNT) | |
523 | return NULL; | |
524 | ||
525 | switch (flag) | |
526 | { | |
527 | case 0: | |
528 | return "Passive state"; | |
529 | case 1: | |
530 | return "Welcome message"; | |
531 | case 2: | |
532 | return "JoinFlood protection"; | |
533 | case 3: | |
534 | return "Queue"; | |
535 | case 4: | |
536 | return "Verbose queue (requires queue)"; | |
537 | case 5: | |
538 | return "Auto queue (requires queue)"; | |
539 | case 6: | |
540 | return "Channel status reporting"; | |
541 | case 7: | |
542 | return "Pattern censor"; | |
543 | case 8: | |
544 | return "Lamer control"; | |
545 | case 9: | |
546 | return "Idle user removal"; | |
547 | case 10: | |
548 | return "Keep channel moderated"; | |
549 | case 11: | |
550 | return "Keep channel invite only"; | |
551 | case 12: | |
552 | return "Handle channel topic"; | |
553 | case 13: | |
554 | return "Calculate statistic"; | |
555 | case 14: | |
556 | return "Remove joining trojans"; | |
557 | case 15: | |
558 | return "Channel commands"; | |
559 | case 16: | |
560 | return "Oper only channel"; | |
561 | case 17: | |
562 | return "Disallow bold, underline, etc."; | |
563 | case 18: | |
564 | return "Queue inactivity deactivation"; | |
565 | case 19: | |
9af95c3d | 566 | return "Require a ticket to join"; |
567 | case 20: | |
135d6084 | 568 | return "Send a message on ticket issue"; |
569 | case 21: | |
570 | return "Excessive highlight prevention"; | |
c86edd1d | 571 | default: |
e908ecfa | 572 | return "Error, please contact strutsi"; |
c86edd1d Q |
573 | } |
574 | } |