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