]> jfr.im git - irc/quakenet/newserv.git/blame - helpmod2/hchannel.c
Whoops, forgot to remove a printf
[irc/quakenet/newserv.git] / helpmod2 / hchannel.c
CommitLineData
c86edd1d
Q
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
19hchannel *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
88int 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
118int 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
125hchannel *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
134hchannel *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
148const char *hchannel_get_state(hchannel* hchan, int mask)
149{
150 if (hchan->flags & mask)
151 return "active";
152 else
153 return "inactive";
154}
155
156const char *hchannel_get_name(hchannel *hchan)
157{
158 return hchan->real_channel->index->name->content;
159}
160
161void hchannel_del_all(void)
162{
163 while (hchannels)
164 hchannel_del(hchannels);
165}
166
167hchannel_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
176hchannel_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
193hchannel_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
211void 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
263void 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
286void hchannel_set_topic(hchannel *hchan)
287{
288 if (hchan->flags & H_HANDLE_TOPIC)
289 helpmod_set_topic(hchan, htopic_construct(hchan->topic));
290}
291
292void 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
302int 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
311int 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
320void 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
349int 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
361int 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
373int 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
382void 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
394void 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
422int 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
431void 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 */
448void 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
467const 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}