]>
Commit | Line | Data |
---|---|---|
1 | ||
2 | #include <stdlib.h> | |
3 | #include <assert.h> | |
4 | #include <string.h> | |
5 | #include <ctype.h> | |
6 | ||
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; | |
49 | hchan->ticket_message = NULL; | |
50 | ||
51 | hchan->last_activity = time(NULL); | |
52 | hchan->last_staff_activity = time(NULL); | |
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); | |
71 | ||
72 | tmp = huser_add_channel(husr, hchan); | |
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 | ||
105 | localpartchannel(helpmodnick, hchan->real_channel, "Channel Removed"); | |
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 | ||
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 | { | |
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) | |
218 | { | |
219 | const char *banmask = hban_ban_string((*hchanuser)->husr->real_user, HBAN_HOST); | |
220 | helpmod_setban(hchan, banmask, time(NULL) + 10 * HDEF_m, MCB_ADD, HLAZY); | |
221 | ||
222 | helpmod_kick(hchan, (*hchanuser)->husr, "Please do not idle in %s", hchannel_get_name(hchan)); | |
223 | continue; | |
224 | } | |
225 | else | |
226 | { | |
227 | 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)); | |
228 | huser_on_channel((*hchanuser)->husr, hchan)->flags |= H_IDLE_WARNING; | |
229 | } | |
230 | } | |
231 | /*hcommit_modes();*/ | |
232 | hchanuser = &(*hchanuser)->next; | |
233 | } | |
234 | hcommit_modes(); | |
235 | } | |
236 | /* Additionally, test if the channel has queue but no idle opers / staff */ | |
237 | if (hchan->flags & H_QUEUE && hchan->flags & H_QUEUE_TIMEOUT) | |
238 | { | |
239 | hchannel_user *tmp; | |
240 | for (tmp = hchan->channel_users;tmp;tmp = tmp->next) | |
241 | if (huser_get_level(tmp->husr) >= H_TRIAL) | |
242 | { | |
243 | huser_channel *huserchan = huser_on_channel(tmp->husr, hchan); | |
244 | if ((time(NULL) - huserchan->last_activity < HELPMOD_QUEUE_TIMEOUT) && (huserchan->last_activity != tmp->time_joined)) | |
245 | break; | |
246 | } | |
247 | if (!tmp) | |
248 | { | |
249 | hchan->flags &= ~H_QUEUE; | |
250 | if (hchan->flags & H_REPORT && hchannel_is_valid(hchan->report_to)) | |
251 | helpmod_message_channel(hchan->report_to, "%s: Channel queue deactivated because of inactivity", hchannel_get_name(hchan)); | |
252 | hchannel_conf_change(hchan, hchan->flags | H_QUEUE); | |
253 | } | |
254 | } | |
255 | } | |
256 | } | |
257 | ||
258 | void hchannel_report(void) | |
259 | { | |
260 | hchannel *hchan = hchannels; | |
261 | for (;hchan;hchan = hchan->next) | |
262 | if (hchan->flags & H_REPORT && !(hchan->flags & H_PASSIVE) && hchannel_is_valid(hchan->report_to)) | |
263 | { | |
264 | int total = hchannel_count_users(hchan, H_ANY); | |
265 | int peons = hchannel_count_users(hchan, H_PEON); | |
266 | int services = hchannel_count_users(hchan, H_SERVICE); | |
267 | ||
268 | if (peons == 0) | |
269 | return; | |
270 | ||
271 | if (hchan->flags & H_QUEUE) | |
272 | { | |
273 | int peons_queue = hchannel_count_queue(hchan); | |
274 | 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))); | |
275 | } | |
276 | else | |
277 | 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"); | |
278 | } | |
279 | } | |
280 | ||
281 | void hchannel_set_topic(hchannel *hchan) | |
282 | { | |
283 | if (hchan->flags & H_HANDLE_TOPIC) | |
284 | helpmod_set_topic(hchan, htopic_construct(hchan->topic)); | |
285 | } | |
286 | ||
287 | void hchannels_match_accounts(void) | |
288 | { | |
289 | hchannel *hchan = hchannels; | |
290 | hchannel_user *hchanuser; | |
291 | for (;hchan;hchan = hchan->next) | |
292 | for (hchanuser = hchan->channel_users;hchanuser;hchanuser = hchanuser->next) | |
293 | if (hchanuser->husr->account == NULL && IsAccount(hchanuser->husr->real_user)) | |
294 | hchanuser->husr->account = haccount_get_by_name(huser_get_auth(hchanuser->husr)); | |
295 | } | |
296 | ||
297 | int hchannels_on_queue(huser *husr) | |
298 | { | |
299 | huser_channel *huserchan = husr->hchannels; | |
300 | for (;huserchan;huserchan = huserchan->next) | |
301 | if (on_queue(husr, huserchan)) | |
302 | return 1; | |
303 | return 0; | |
304 | } | |
305 | ||
306 | int hchannels_on_desk(struct huser_struct* husr) | |
307 | { | |
308 | huser_channel *huserchan = husr->hchannels; | |
309 | for (;huserchan;huserchan = huserchan->next) | |
310 | if (on_desk(husr, huserchan)) | |
311 | return 1; | |
312 | return 0; | |
313 | } | |
314 | ||
315 | void hchannels_dnmo(struct huser_struct *husr) | |
316 | { | |
317 | hchannel *hchan = hchannels; | |
318 | for (;hchan;hchan = hchan->next) | |
319 | { | |
320 | huser_channel *huserchan = huser_on_channel(husr, hchan); | |
321 | /*if (on_queue(husr, huserchan) || on_desk(husr, huserchan))*/ | |
322 | if (huserchan != NULL) | |
323 | { | |
324 | hchannel_user *tmp = NULL, **hchanuser = &hchan->channel_users; | |
325 | for (;*hchanuser;hchanuser = &(*hchanuser)->next) | |
326 | if ((*hchanuser)->husr == husr) | |
327 | { | |
328 | tmp = *hchanuser; | |
329 | *hchanuser = (*hchanuser)->next; | |
330 | if (!*hchanuser) | |
331 | break; | |
332 | } | |
333 | *hchanuser = tmp; | |
334 | assert(*hchanuser != NULL); | |
335 | (*hchanuser)->next = NULL; | |
336 | if (on_desk(husr, huserchan)) | |
337 | { | |
338 | helpmod_channick_modes(husr, hchan, MC_DEVOICE, HLAZY); | |
339 | huserchan->flags &= ~HQUEUE_DONE; | |
340 | } | |
341 | } | |
342 | } | |
343 | } | |
344 | ||
345 | int hchannel_count_users(hchannel *hchan, hlevel lvl) | |
346 | { | |
347 | int count = 0; | |
348 | hchannel_user *hchanuser = hchan->channel_users; | |
349 | for (;hchanuser;hchanuser = hchanuser->next) | |
350 | if (lvl == H_ANY) | |
351 | count++; | |
352 | else if (huser_get_level(hchanuser->husr) == lvl) | |
353 | count++; | |
354 | return count; | |
355 | } | |
356 | ||
357 | int hchannel_count_queue(hchannel *hchan) | |
358 | { | |
359 | int count = 0; | |
360 | hchannel_user *hchanuser = hchan->channel_users; | |
361 | for (;hchanuser;hchanuser = hchanuser->next) | |
362 | { | |
363 | if (on_queue(hchanuser->husr, huser_on_channel(hchanuser->husr, hchan))) | |
364 | count++; | |
365 | } | |
366 | return count; | |
367 | } | |
368 | ||
369 | int hchannel_is_valid(hchannel *hchan) | |
370 | { | |
371 | hchannel *ptr = hchannels; | |
372 | for (;ptr;ptr = ptr->next) | |
373 | if (hchan == ptr) | |
374 | return 1; | |
375 | return 0; | |
376 | } | |
377 | ||
378 | void hchannel_mode_check(hchannel *hchan) | |
379 | { | |
380 | if (((hchan->flags & H_MAINTAIN_M) || (hchan->flags & H_QUEUE)) && !IsModerated(hchan->real_channel)) | |
381 | helpmod_simple_modes(hchan, CHANMODE_MODERATE, 0,0); | |
382 | else if (!((hchan->flags & H_MAINTAIN_M) || (hchan->flags & H_QUEUE)) && IsModerated(hchan->real_channel)) | |
383 | helpmod_simple_modes(hchan, 0, CHANMODE_MODERATE ,0); | |
384 | if (hchan->flags & H_MAINTAIN_I && !IsInviteOnly(hchan->real_channel)) | |
385 | helpmod_simple_modes(hchan, CHANMODE_INVITEONLY, 0,0); | |
386 | else if (!(hchan->flags & H_MAINTAIN_I) && IsInviteOnly(hchan->real_channel)) | |
387 | helpmod_simple_modes(hchan, 0, CHANMODE_INVITEONLY, 0); | |
388 | } | |
389 | ||
390 | void hchannel_conf_change(hchannel *hchan, int old_flags) | |
391 | { | |
392 | int i; | |
393 | hflagchange change; | |
394 | ||
395 | for (i=0;i<HCHANNEL_CONF_COUNT;i++) | |
396 | { | |
397 | if ((hchan->flags ^ old_flags) & (1 << i)) | |
398 | { | |
399 | change = (hchan->flags & (1 << i))?H_ON:H_OFF; | |
400 | switch (1 << i) | |
401 | { | |
402 | case H_QUEUE: | |
403 | hchannel_mode_check(hchan); | |
404 | if (change == H_ON) | |
405 | helpmod_message_channel(hchan, "Channel queue has been activated, all users enqueued"); | |
406 | else | |
407 | helpmod_message_channel(hchan, "Channel queue has been deactivated"); | |
408 | break; | |
409 | case H_MAINTAIN_I: | |
410 | case H_MAINTAIN_M: | |
411 | hchannel_mode_check(hchan); | |
412 | break; | |
413 | } | |
414 | } | |
415 | } | |
416 | } | |
417 | ||
418 | int hchannel_count(void) | |
419 | { | |
420 | hchannel *hchan = hchannels; | |
421 | int count = 0; | |
422 | for (;hchan;hchan = hchan->next) | |
423 | count++; | |
424 | return count; | |
425 | } | |
426 | ||
427 | void hchannel_activate_join_flood(hchannel *hchan) | |
428 | { | |
429 | hchannel_user **hchanuser = &hchan->channel_users; | |
430 | helpmod_simple_modes(hchan, CHANMODE_REGONLY, 0, 1); | |
431 | ||
432 | /* clean the channel of the already joined clients */ | |
433 | while (*hchanuser) | |
434 | if (((*hchanuser)->time_joined > (time(NULL) - 5)) && huser_get_level((*hchanuser)->husr) < H_STAFF) | |
435 | helpmod_kick(hchan, (*hchanuser)->husr, "Join flood"); | |
436 | else | |
437 | hchanuser = &(*hchanuser)->next; | |
438 | ||
439 | hchan->flags |= H_JOIN_FLOOD; | |
440 | ||
441 | scheduleoneshot(time(NULL) + 60, &hchannel_deactivate_join_flood, NULL); | |
442 | } | |
443 | ||
444 | /* goes to schedule */ | |
445 | void hchannel_deactivate_join_flood() | |
446 | { | |
447 | hchannel *hchan = hchannels; | |
448 | for (;hchan;hchan = hchan->next) | |
449 | if (hchan->flags & H_JOIN_FLOOD) | |
450 | { | |
451 | helpmod_simple_modes(hchan, 0, CHANMODE_REGONLY, 1); | |
452 | hchan->flags &= ~H_JOIN_FLOOD; | |
453 | } | |
454 | } | |
455 | ||
456 | const char *hchannel_get_state(hchannel* hchan, int mask) | |
457 | { | |
458 | if (hchan->flags & mask) | |
459 | return "Yes"; | |
460 | else | |
461 | return "No"; | |
462 | } | |
463 | ||
464 | int hchannel_highlight_detection(hchannel *hchan, const char *message) | |
465 | { | |
466 | char buffer[512], *buffer_ptr = buffer, *ptr = buffer; | |
467 | int i, matches = 0; | |
468 | ||
469 | strcpy(buffer, message); | |
470 | ||
471 | /* remove commas */ | |
472 | for (i=0;i<512 && buffer[i] != '\0';i++) | |
473 | if (buffer[i] == ',') | |
474 | buffer[i] = ' '; | |
475 | ||
476 | /* reset i for loop */ | |
477 | i = 0; | |
478 | do | |
479 | { | |
480 | nick *tmp; | |
481 | huser *tmp_huser; | |
482 | huser_channel *tmp_huserchan; | |
483 | ||
484 | if (i++ > 6) | |
485 | break; | |
486 | ||
487 | while (*buffer_ptr && isspace(*buffer_ptr)) | |
488 | buffer_ptr++; | |
489 | ||
490 | if (*buffer_ptr == '@') | |
491 | buffer_ptr++; | |
492 | ||
493 | if (*buffer_ptr) | |
494 | { | |
495 | ptr = strchr(buffer_ptr, ' '); | |
496 | if (ptr) | |
497 | { | |
498 | *ptr = '\0'; | |
499 | ptr++; | |
500 | } | |
501 | if ((tmp = getnickbynick(buffer_ptr))) | |
502 | if ((tmp_huser = huser_get(tmp))) | |
503 | if ((tmp_huserchan = huser_on_channel(tmp_huser, hchan))) | |
504 | if ((tmp_huserchan->flags & HCUMODE_OP) && strlen(huser_get_nick(tmp_huser)) > 1) | |
505 | matches++; | |
506 | } | |
507 | if (ptr == NULL) | |
508 | break; | |
509 | else | |
510 | buffer_ptr = ptr; | |
511 | } while (*ptr); | |
512 | ||
513 | if (matches > 2) | |
514 | return 1; | |
515 | else | |
516 | return 0; | |
517 | } | |
518 | ||
519 | const char *hchannel_get_sname(int flag) | |
520 | { | |
521 | if (flag < 0 || flag > HCHANNEL_CONF_COUNT) | |
522 | return NULL; | |
523 | ||
524 | switch (flag) | |
525 | { | |
526 | case 0: | |
527 | return "Passive state"; | |
528 | case 1: | |
529 | return "Welcome message"; | |
530 | case 2: | |
531 | return "JoinFlood protection"; | |
532 | case 3: | |
533 | return "Queue"; | |
534 | case 4: | |
535 | return "Verbose queue (requires queue)"; | |
536 | case 5: | |
537 | return "Auto queue (requires queue)"; | |
538 | case 6: | |
539 | return "Channel status reporting"; | |
540 | case 7: | |
541 | return "Pattern censor"; | |
542 | case 8: | |
543 | return "Lamer control"; | |
544 | case 9: | |
545 | return "Idle user removal"; | |
546 | case 10: | |
547 | return "Keep channel moderated"; | |
548 | case 11: | |
549 | return "Keep channel invite only"; | |
550 | case 12: | |
551 | return "Handle channel topic"; | |
552 | case 13: | |
553 | return "Calculate statistic"; | |
554 | case 14: | |
555 | return "Remove joining trojans"; | |
556 | case 15: | |
557 | return "Channel commands"; | |
558 | case 16: | |
559 | return "Oper only channel"; | |
560 | case 17: | |
561 | return "Disallow bold, underline, etc."; | |
562 | case 18: | |
563 | return "Queue inactivity deactivation"; | |
564 | case 19: | |
565 | return "Require a ticket to join"; | |
566 | case 20: | |
567 | return "Send a message on ticket issue"; | |
568 | case 21: | |
569 | return "Excessive highlight prevention"; | |
570 | default: | |
571 | return "Error, please contact strutsi"; | |
572 | } | |
573 | } |