1 /*
2  * userchan.c -- part of channels.mod
3  *
4  * $Id: userchan.c,v 1.44 (1.0.1) 2004/03/24 23:44:23 [Xp-AvR] Exp $
5  */
6 
get_chanrec(struct userrec * u,char * chname)7 struct chanuserrec *get_chanrec(struct userrec *u, char *chname)
8 {
9   struct chanuserrec *ch;
10 
11   for (ch = u->chanrec; ch; ch = ch->next)
12     if (!rfc_casecmp(ch->channel, chname))
13       return ch;
14   return NULL;
15 }
16 
add_chanrec(struct userrec * u,char * chname)17 static struct chanuserrec *add_chanrec(struct userrec *u, char *chname)
18 {
19   struct chanuserrec *ch = NULL;
20 
21   if (findchan_by_dname(chname)) {
22     ch = user_malloc(sizeof(struct chanuserrec));
23 
24     ch->next = u->chanrec;
25     u->chanrec = ch;
26     ch->info = NULL;
27     ch->flags = 0;
28     ch->flags_udef = 0;
29     ch->laston = 0;
30     strncpy(ch->channel, chname, 81);
31     ch->channel[80] = 0;
32     if (!noshare && !(u->flags & USER_UNSHARED))
33       shareout(findchan_by_dname(chname), "+cr %s %s\n", u->handle, chname);
34   }
35   return ch;
36 }
37 
add_chanrec_by_handle(struct userrec * bu,char * hand,char * chname)38 static void add_chanrec_by_handle(struct userrec *bu, char *hand, char *chname)
39 {
40   struct userrec *u;
41 
42   u = get_user_by_handle(bu, hand);
43   if (!u)
44     return;
45   if (!get_chanrec(u, chname))
46     add_chanrec(u, chname);
47 }
48 
get_handle_chaninfo(char * handle,char * chname,char * s)49 static void get_handle_chaninfo(char *handle, char *chname, char *s)
50 {
51   struct userrec *u;
52   struct chanuserrec *ch;
53 
54   u = get_user_by_handle(userlist, handle);
55   if (u == NULL) {
56     s[0] = 0;
57     return;
58   }
59   ch = get_chanrec(u, chname);
60   if (ch == NULL) {
61     s[0] = 0;
62     return;
63   }
64   if (ch->info == NULL) {
65     s[0] = 0;
66     return;
67   }
68   strcpy(s, ch->info);
69   return;
70 }
71 
set_handle_chaninfo(struct userrec * bu,char * handle,char * chname,char * info)72 static void set_handle_chaninfo(struct userrec *bu, char *handle,
73                                 char *chname, char *info)
74 {
75   struct userrec *u;
76   struct chanuserrec *ch;
77   struct chanset_t *cst;
78 
79   u = get_user_by_handle(bu, handle);
80   if (!u)
81     return;
82   ch = get_chanrec(u, chname);
83   if (!ch) {
84     add_chanrec_by_handle(bu, handle, chname);
85     ch = get_chanrec(u, chname);
86   }
87   if (info) {
88     if (strlen(info) > 80)
89       info[80] = 0;
90   }
91   if (ch->info != NULL)
92     nfree(ch->info);
93   if (info && info[0]) {
94     ch->info = (char *) user_malloc(strlen(info) + 1);
95     strcpy(ch->info, info);
96   } else
97     ch->info = NULL;
98   cst = findchan_by_dname(chname);
99   if ((!noshare) && (bu == userlist) &&
100       !(u->flags & (USER_UNSHARED | USER_BOT)) && share_greet) {
101     shareout(cst, "chchinfo %s %s %s\n", handle, chname, info ? info : "");
102   }
103 }
104 
del_chanrec(struct userrec * u,char * chname)105 static void del_chanrec(struct userrec *u, char *chname)
106 {
107   struct chanuserrec *ch = u->chanrec, *lst = NULL;
108 
109   while (ch) {
110     if (!rfc_casecmp(chname, ch->channel)) {
111       if (lst == NULL)
112         u->chanrec = ch->next;
113       else
114         lst->next = ch->next;
115       if (ch->info != NULL)
116         nfree(ch->info);
117       nfree(ch);
118       if (!noshare && !(u->flags & USER_UNSHARED))
119         shareout(findchan_by_dname(chname), "-cr %s %s\n", u->handle, chname);
120       return;
121     }
122     lst = ch;
123     ch = ch->next;
124   }
125 }
126 
set_handle_laston(char * chan,struct userrec * u,time_t n)127 static void set_handle_laston(char *chan, struct userrec *u, time_t n)
128 {
129   struct chanuserrec *ch;
130 
131   if (!u)
132     return;
133   touch_laston(u, chan, n);
134   ch = get_chanrec(u, chan);
135   if (!ch)
136     return;
137   ch->laston = n;
138 }
139 
140 /* Is this mask sticky? */
u_sticky_mask(maskrec * u,char * uhost)141 static int u_sticky_mask(maskrec *u, char *uhost)
142 {
143   for (; u; u = u->next)
144     if (!rfc_casecmp(u->mask, uhost))
145       return (u->flags & MASKREC_STICKY);
146   return 0;
147 }
148 
149 /* Set sticky attribute for a mask. */
u_setsticky_mask(struct chanset_t * chan,maskrec * u,char * uhost,int sticky,char * botcmd)150 static int u_setsticky_mask(struct chanset_t *chan, maskrec *u, char *uhost,
151                             int sticky, char *botcmd)
152 {
153   int j;
154 
155   if (str_isdigit(uhost))
156     j = atoi(uhost);
157   else
158     j = -1;
159   while (u) {
160     if (j >= 0)
161       j--;
162 
163     if (!j || ((j < 0) && !rfc_casecmp(u->mask, uhost))) {
164       if (sticky > 0)
165         u->flags |= MASKREC_STICKY;
166       else if (!sticky)
167         u->flags &= ~MASKREC_STICKY;
168       else
169         return 0;
170       if (!j)
171         strcpy(uhost, u->mask);
172 
173       if (!noshare)
174         shareout(chan, "%s %s %d %s\n", botcmd, uhost, sticky,
175                  (chan) ? chan->dname : "");
176       return 1;
177     }
178 
179     u = u->next;
180   }
181   if (j >= 0)
182     return -j;
183 
184   return 0;
185 }
186 
187 /* Merge of u_equals_ban(), u_equals_exempt() and u_equals_invite(). */
u_equals_mask(maskrec * u,char * mask)188 static int u_equals_mask(maskrec *u, char *mask)
189 {
190   for (; u; u = u->next)
191     if (!rfc_casecmp(u->mask, mask)) {
192       if (u->flags & MASKREC_PERM)
193         return 2;
194       else
195         return 1;
196     }
197   return 0;
198 }
199 
u_match_mask(maskrec * rec,char * mask)200 static int u_match_mask(maskrec *rec, char *mask)
201 {
202   for (; rec; rec = rec->next)
203     if (wild_match(rec->mask, mask))
204       return 1;
205   return 0;
206 }
207 
u_delban(struct chanset_t * c,char * who,int doit)208 static int u_delban(struct chanset_t *c, char *who, int doit)
209 {
210   int j, i = 0;
211   maskrec *t;
212   maskrec **u = (c) ? &c->bans : &global_bans;
213   char temp[256];
214 
215   if (!strchr(who, '!') && str_isdigit(who)) {
216     j = atoi(who);
217     j--;
218     for (; (*u) && j; u = &((*u)->next), j--);
219     if (*u) {
220       strncpyz(temp, (*u)->mask, sizeof temp);
221       i = 1;
222     } else
223       return -j - 1;
224   } else {
225     for (; *u && !i; u = &((*u)->next))
226       if (!rfc_casecmp((*u)->mask, who)) {
227         strncpyz(temp, who, sizeof temp);
228         i = 1;
229         break;
230       }
231     if (!*u)
232       return 0;
233   }
234   if (i && doit) {
235     if (!noshare) {
236       char *mask = str_escape(temp, ':', '\\');
237 
238       if (mask) {
239         if (c)
240           shareout(c, "-bc %s %s\n", c->dname, mask);
241         else
242           shareout(NULL, "-b %s\n", mask);
243         nfree(mask);
244       }
245     }
246     if (lastdeletedmask)
247       nfree(lastdeletedmask);
248     lastdeletedmask = nmalloc(strlen((*u)->mask) + 1);
249     strcpy(lastdeletedmask, (*u)->mask);
250     nfree((*u)->mask);
251     if ((*u)->desc)
252       nfree((*u)->desc);
253     if ((*u)->user)
254       nfree((*u)->user);
255     t = *u;
256     *u = (*u)->next;
257     nfree(t);
258   }
259   return i;
260 }
261 
u_delexempt(struct chanset_t * c,char * who,int doit)262 static int u_delexempt(struct chanset_t *c, char *who, int doit)
263 {
264   int j, i = 0;
265   maskrec *t, **u = c ? &(c->exempts) : &global_exempts;
266   char temp[256];
267 
268   if (!strchr(who, '!') && str_isdigit(who)) {
269     j = atoi(who);
270     j--;
271     for (; (*u) && j; u = &((*u)->next), j--);
272     if (*u) {
273       strncpyz(temp, (*u)->mask, sizeof temp);
274       i = 1;
275     } else
276       return -j - 1;
277   } else {
278     for (; *u && !i; u = &((*u)->next))
279       if (!rfc_casecmp((*u)->mask, who)) {
280         strncpyz(temp, who, sizeof temp);
281         i = 1;
282         break;
283       }
284     if (!*u)
285       return 0;
286   }
287   if (i && doit) {
288     if (!noshare) {
289       char *mask = str_escape(temp, ':', '\\');
290 
291       if (mask) {
292         if (c)
293           shareout(c, "-ec %s %s\n", c->dname, mask);
294         else
295           shareout(NULL, "-e %s\n", mask);
296         nfree(mask);
297       }
298     }
299     if (lastdeletedmask)
300       nfree(lastdeletedmask);
301     lastdeletedmask = nmalloc(strlen((*u)->mask) + 1);
302     strcpy(lastdeletedmask, (*u)->mask);
303     nfree((*u)->mask);
304     if ((*u)->desc)
305       nfree((*u)->desc);
306     if ((*u)->user)
307       nfree((*u)->user);
308     t = *u;
309     *u = (*u)->next;
310     nfree(t);
311   }
312   return i;
313 }
314 
u_delinvite(struct chanset_t * c,char * who,int doit)315 static int u_delinvite(struct chanset_t *c, char *who, int doit)
316 {
317   int j, i = 0;
318   maskrec *t;
319   maskrec **u = c ? &(c->invites) : &global_invites;
320   char temp[256];
321 
322   if (!strchr(who, '!') && str_isdigit(who)) {
323     j = atoi(who);
324     j--;
325     for (; (*u) && j; u = &((*u)->next), j--);
326     if (*u) {
327       strncpyz(temp, (*u)->mask, sizeof temp);
328       i = 1;
329     } else
330       return -j - 1;
331   } else {
332     for (; *u && !i; u = &((*u)->next))
333       if (!rfc_casecmp((*u)->mask, who)) {
334         strncpyz(temp, who, sizeof temp);
335         i = 1;
336         break;
337       }
338     if (!*u)
339       return 0;
340   }
341   if (i && doit) {
342     if (!noshare) {
343       char *mask = str_escape(temp, ':', '\\');
344 
345       if (mask) {
346         if (c)
347           shareout(c, "-invc %s %s\n", c->dname, mask);
348         else
349           shareout(NULL, "-inv %s\n", mask);
350         nfree(mask);
351       }
352     }
353     if (lastdeletedmask)
354       nfree(lastdeletedmask);
355     lastdeletedmask = nmalloc(strlen((*u)->mask) + 1);
356     strcpy(lastdeletedmask, (*u)->mask);
357     nfree((*u)->mask);
358     if ((*u)->desc)
359       nfree((*u)->desc);
360     if ((*u)->user)
361       nfree((*u)->user);
362     t = *u;
363     *u = (*u)->next;
364     nfree(t);
365   }
366   return i;
367 }
368 
369 /* Note: If first char of note is '*' it's a sticky ban. */
u_addban(struct chanset_t * chan,char * ban,char * from,char * note,time_t expire_time,int flags)370 static int u_addban(struct chanset_t *chan, char *ban, char *from, char *note,
371                     time_t expire_time, int flags)
372 {
373   char host[1024], s[1024], myhost[1024], ident[21], nick[1024], *p0;
374   maskrec *p = NULL, *l, **u = chan ? &chan->bans : &global_bans;
375   module_entry *me;
376   struct userrec *ul;
377   struct list_type *q;
378   struct flag_record user, plus, minus;
379   int ok = 1, f = 0;
380 
381   strcpy(host, ban);
382 
383 /* Proper banning & ident check */
384   p0 = strchr(host, '@');
385   strcpy(myhost, &p0[1]);
386   p0 = strchr(host, '!');
387   strcpy(ident, &p0[1]);
388   ident[strlen(ident) - strlen(myhost) - 1] = 0;
389   strcpy(nick, host);
390   nick[strlen(p0) - strlen(ident) - strlen(myhost) - 1] = 0;
391   if (strlen(ident) > 10)
392     ident[10] = 0;
393   sprintf(host, "%s!%s@%s", nick, ident, myhost);
394 /* */
395 
396   if ((strchr(host, '!') == NULL) && (strchr(host, '@') == NULL))
397     strcat(host, "!*@*");
398   else if (strchr(host, '@') == NULL)
399     strcat(host, "@*");
400   else if (strchr(host, '!') == NULL) {
401     char *i = strchr(host, '@');
402 
403     strcpy(s, i);
404     *i = 0;
405     strcat(host, "!*");
406     strcat(host, s);
407   }
408 
409   if ((me = module_find("server", 0, 0)) && me->funcs)
410     simple_sprintf(s, "%s!%s", me->funcs[SERVER_BOTNAME],
411                    me->funcs[SERVER_BOTUSERHOST]);
412   else
413     simple_sprintf(s, "%s!%s@%s", origbotname, botuser, hostname);
414   if (wild_match(host, s)) {
415     putlog(LOG_MISC, "*", IRC_IBANNEDME);
416     return 0;
417   }
418 
419   plus.match = FR_GLOBAL | FR_CHAN | FR_BOT;
420   break_down_flags("b", &plus, &minus);
421   f = (minus.global ||minus.udef_global || minus.chan || minus.udef_chan || minus.bot);
422   minus.match = plus.match ^ (FR_AND | FR_OR);
423   for (ul = userlist; ul; ul = ul->next) {
424     user.match = FR_GLOBAL | FR_CHAN | FR_BOT;
425     get_user_flagrec(ul, &user, NULL);
426     if (flagrec_eq(&plus, &user) && !(f && flagrec_eq(&minus, &user)))
427       ok = 1;
428     else
429       ok = 0;
430     if (ok) {
431       for (q = get_user(&USERENTRY_HOSTS, ul); q; q = q->next)
432         if (wild_match(q->extra, host)) {
433           debug2("(userchan.c->u_addban) ban %s matches to one of the bots: %s", host, q->extra);
434           return 0;
435         }
436     }
437   }
438 
439   if (expire_time == now)
440     return 1;
441 
442   for (l = *u; l; l = l->next)
443     if (!rfc_casecmp(l->mask, host)) {
444       p = l;
445       break;
446     }
447 
448   if (note[0] == '*') {
449     flags |= MASKREC_STICKY;
450     note++;
451   }
452   if ((expire_time == 0L) || (flags & MASKREC_PERM)) {
453     flags |= MASKREC_PERM;
454     expire_time = 0L;
455   }
456 
457   if (p == NULL) {
458     p = user_malloc(sizeof(maskrec));
459     p->next = *u;
460     *u = p;
461   } else {
462     nfree(p->mask);
463     nfree(p->user);
464     nfree(p->desc);
465   }
466   p->expire = expire_time;
467   p->added = now;
468   p->lastactive = 0;
469   p->flags = flags;
470   p->mask = user_malloc(strlen(host) + 1);
471   strcpy(p->mask, host);
472   p->user = user_malloc(strlen(from) + 1);
473   strcpy(p->user, from);
474   p->desc = user_malloc(strlen(note) + 1);
475   strcpy(p->desc, note);
476   if (!noshare) {
477     char *mask = str_escape(host, ':', '\\');
478 
479     if (mask) {
480       if (strcmp(mask, "*!*@*") != 0) {
481         if (!chan)
482           shareout(NULL, "+b %s %lu %s%s %s %s\n", mask, expire_time - now,
483                    (flags & MASKREC_STICKY) ? "s" : "",
484                    (flags & MASKREC_PERM) ? "p" : "-", from, note);
485         else
486           shareout(chan, "+bc %s %lu %s %s%s %s %s\n", mask, expire_time - now,
487                    chan->dname, (flags & MASKREC_STICKY) ? "s" : "",
488                    (flags & MASKREC_PERM) ? "p" : "-", from, note);
489       }
490       nfree(mask);
491     }
492   }
493   return 1;
494 }
495 
496 /* Note: If first char of note is '*' it's a sticky invite. */
u_addinvite(struct chanset_t * chan,char * invite,char * from,char * note,time_t expire_time,int flags)497 static int u_addinvite(struct chanset_t *chan, char *invite, char *from,
498                        char *note, time_t expire_time, int flags)
499 {
500   char host[1024], s[1024], myhost[1024], ident[21], nick[1024], *p0;
501   maskrec *p = NULL, *l, **u = chan ? &chan->invites : &global_invites;
502   module_entry *me;
503 
504   strcpy(host, invite);
505 
506 /* Proper banning & ident check */
507   p0 = strchr(host, '@');
508   strcpy(myhost, &p0[1]);
509   p0 = strchr(host, '!');
510   strcpy(ident, &p0[1]);
511   ident[strlen(ident) - strlen(myhost) - 1] = 0;
512   strcpy(nick, host);
513   nick[strlen(p0) - strlen(ident) - strlen(myhost) - 1] = 0;
514   if (strlen(ident) > 10)
515     ident[10] = 0;
516   sprintf(host, "%s!%s@%s", nick, ident, myhost);
517 /* */
518 
519   if ((strchr(host, '!') == NULL) && (strchr(host, '@') == NULL))
520     strcat(host, "!*@*");
521   else if (strchr(host, '@') == NULL)
522     strcat(host, "@*");
523   else if (strchr(host, '!') == NULL) {
524     char *i = strchr(host, '@');
525 
526     strcpy(s, i);
527     *i = 0;
528     strcat(host, "!*");
529     strcat(host, s);
530   }
531   if ((me = module_find("server", 0, 0)) && me->funcs)
532     simple_sprintf(s, "%s!%s", me->funcs[SERVER_BOTNAME],
533                    me->funcs[SERVER_BOTUSERHOST]);
534   else
535     simple_sprintf(s, "%s!%s@%s", origbotname, botuser, hostname);
536 
537   for (l = *u; l; l = l->next)
538     if (!rfc_casecmp(l->mask, host)) {
539       p = l;
540       break;
541     }
542 
543   if (note[0] == '*') {
544     flags |= MASKREC_STICKY;
545     note++;
546   }
547   if ((expire_time == 0L) || (flags & MASKREC_PERM)) {
548     flags |= MASKREC_PERM;
549     expire_time = 0L;
550   }
551 
552   if (p == NULL) {
553     p = user_malloc(sizeof(maskrec));
554     p->next = *u;
555     *u = p;
556   } else {
557     nfree(p->mask);
558     nfree(p->user);
559     nfree(p->desc);
560   }
561   p->expire = expire_time;
562   p->added = now;
563   p->lastactive = 0;
564   p->flags = flags;
565   p->mask = user_malloc(strlen(host) + 1);
566   strcpy(p->mask, host);
567   p->user = user_malloc(strlen(from) + 1);
568   strcpy(p->user, from);
569   p->desc = user_malloc(strlen(note) + 1);
570   strcpy(p->desc, note);
571   if (!noshare) {
572     char *mask = str_escape(host, ':', '\\');
573 
574     if (mask) {
575       if (!chan)
576         shareout(NULL, "+inv %s %lu %s%s %s %s\n", mask, expire_time - now,
577                  (flags & MASKREC_STICKY) ? "s" : "",
578                  (flags & MASKREC_PERM) ? "p" : "-", from, note);
579       else
580         shareout(chan, "+invc %s %lu %s %s%s %s %s\n", mask, expire_time - now,
581                  chan->dname, (flags & MASKREC_STICKY) ? "s" : "",
582                  (flags & MASKREC_PERM) ? "p" : "-", from, note);
583       nfree(mask);
584     }
585   }
586   return 1;
587 }
588 
589 /* Note: If first char of note is '*' it's a sticky exempt. */
u_addexempt(struct chanset_t * chan,char * exempt,char * from,char * note,time_t expire_time,int flags)590 static int u_addexempt(struct chanset_t *chan, char *exempt, char *from,
591                        char *note, time_t expire_time, int flags)
592 {
593   char host[1024], s[1024], myhost[1024], ident[21], nick[1024], *p0;
594   maskrec *p = NULL, *l, **u = chan ? &chan->exempts : &global_exempts;
595   module_entry *me;
596 
597   strcpy(host, exempt);
598 
599 /* Proper banning & ident check */
600   p0 = strchr(host, '@');
601   strcpy(myhost, &p0[1]);
602   p0 = strchr(host, '!');
603   strcpy(ident, &p0[1]);
604   ident[strlen(ident) - strlen(myhost) - 1] = 0;
605   strcpy(nick, host);
606   nick[strlen(p0) - strlen(ident) - strlen(myhost) - 1] = 0;
607   if (strlen(ident) > 10)
608     ident[10] = 0;
609   sprintf(host, "%s!%s@%s", nick, ident, myhost);
610 /* */
611 
612   if ((strchr(host, '!') == NULL) && (strchr(host, '@') == NULL))
613     strcat(host, "!*@*");
614   else if (strchr(host, '@') == NULL)
615     strcat(host, "@*");
616   else if (strchr(host, '!') == NULL) {
617     char *i = strchr(host, '@');
618 
619     strcpy(s, i);
620     *i = 0;
621     strcat(host, "!*");
622     strcat(host, s);
623   }
624   if ((me = module_find("server", 0, 0)) && me->funcs)
625     simple_sprintf(s, "%s!%s", me->funcs[SERVER_BOTNAME],
626                    me->funcs[SERVER_BOTUSERHOST]);
627   else
628     simple_sprintf(s, "%s!%s@%s", origbotname, botuser, hostname);
629 
630   for (l = *u; l; l = l->next)
631     if (!rfc_casecmp(l->mask, host)) {
632       p = l;
633       break;
634     }
635 
636   if (note[0] == '*') {
637     flags |= MASKREC_STICKY;
638     note++;
639   }
640   if ((expire_time == 0L) || (flags & MASKREC_PERM)) {
641     flags |= MASKREC_PERM;
642     expire_time = 0L;
643   }
644 
645   if (p == NULL) {
646     p = user_malloc(sizeof(maskrec));
647     p->next = *u;
648     *u = p;
649   } else {
650     nfree(p->mask);
651     nfree(p->user);
652     nfree(p->desc);
653   }
654   p->expire = expire_time;
655   p->added = now;
656   p->lastactive = 0;
657   p->flags = flags;
658   p->mask = user_malloc(strlen(host) + 1);
659   strcpy(p->mask, host);
660   p->user = user_malloc(strlen(from) + 1);
661   strcpy(p->user, from);
662   p->desc = user_malloc(strlen(note) + 1);
663   strcpy(p->desc, note);
664   if (!noshare) {
665     char *mask = str_escape(host, ':', '\\');
666 
667     if (mask) {
668       if (!chan)
669         shareout(NULL, "+e %s %lu %s%s %s %s\n", mask, expire_time - now,
670                  (flags & MASKREC_STICKY) ? "s" : "",
671                  (flags & MASKREC_PERM) ? "p" : "-", from, note);
672       else
673         shareout(chan, "+ec %s %lu %s %s%s %s %s\n", mask, expire_time - now,
674                  chan->dname, (flags & MASKREC_STICKY) ? "s" : "",
675                  (flags & MASKREC_PERM) ? "p" : "-", from, note);
676       nfree(mask);
677     }
678   }
679   return 1;
680 }
681 
682 /* Take host entry from ban list and display it ban-style. */
display_ban(int idx,int number,maskrec * ban,struct chanset_t * chan,int show_inact)683 static void display_ban(int idx, int number, maskrec *ban,
684                         struct chanset_t *chan, int show_inact)
685 {
686   char dates[81], s[41];
687 
688   if (ban->added) {
689     daysago(now, ban->added, s);
690     sprintf(dates, "%s %s", MODES_CREATED, s);
691     if (ban->added < ban->lastactive) {
692       strcat(dates, ", ");
693       strcat(dates, MODES_LASTUSED);
694       strcat(dates, " ");
695       daysago(now, ban->lastactive, s);
696       strcat(dates, s);
697     }
698   } else
699     dates[0] = 0;
700   if (ban->flags & MASKREC_PERM)
701     strcpy(s, "(expires: never)");
702   else {
703     char s1[41];
704 
705     strftime(s1, 23, "%d.%m.%Y %H:%M:%S", localtime(&ban->expire));
706     sprintf(s, "(expires: %s)", s1);
707   }
708   if (ban->flags & MASKREC_STICKY)
709     strcat(s, " (sticky)");
710   if (!chan || ischanban(chan, ban->mask)) {
711     if (number >= 0)
712       dprintf(idx, "  [%3d] %s %s\n", number, ban->mask, s);
713     else
714       dprintf(idx, "BAN: %s %s\n", ban->mask, s);
715   } else if (show_inact) {
716     if (number >= 0)
717       dprintf(idx, "! [%3d] %s %s\n", number, ban->mask, s);
718     else
719       dprintf(idx, "BAN (%s): %s %s\n", MODES_INACTIVE, ban->mask, s);
720   } else
721     return;
722   dprintf(idx, "        %s: %s\n", ban->user, ban->desc);
723   if (dates[0])
724     dprintf(idx, "        %s\n", dates);
725 }
726 
727 /* Take host entry from exempt list and display it ban-style. */
display_exempt(int idx,int number,maskrec * exempt,struct chanset_t * chan,int show_inact)728 static void display_exempt(int idx, int number, maskrec *exempt,
729                            struct chanset_t *chan, int show_inact)
730 {
731   char dates[81], s[41];
732 
733   if (exempt->added) {
734     daysago(now, exempt->added, s);
735     sprintf(dates, "%s %s", MODES_CREATED, s);
736     if (exempt->added < exempt->lastactive) {
737       strcat(dates, ", ");
738       strcat(dates, MODES_LASTUSED);
739       strcat(dates, " ");
740       daysago(now, exempt->lastactive, s);
741       strcat(dates, s);
742     }
743   } else
744     dates[0] = 0;
745   if (exempt->flags & MASKREC_PERM)
746     strcpy(s, "(expires: never)");
747   else {
748     char s1[41];
749 
750     strftime(s1, 23, "%d.%m.%Y %H:%M:%S", localtime(&exempt->expire));
751     sprintf(s, "(expires: %s)", s1);
752   }
753   if (exempt->flags & MASKREC_STICKY)
754     strcat(s, " (sticky)");
755   if (!chan || ischanexempt(chan, exempt->mask)) {
756     if (number >= 0)
757       dprintf(idx, "  [%3d] %s %s\n", number, exempt->mask, s);
758     else
759       dprintf(idx, "EXEMPT: %s %s\n", exempt->mask, s);
760   } else if (show_inact) {
761     if (number >= 0)
762       dprintf(idx, "! [%3d] %s %s\n", number, exempt->mask, s);
763     else
764       dprintf(idx, "EXEMPT (%s): %s %s\n", MODES_INACTIVE, exempt->mask, s);
765   } else
766     return;
767   dprintf(idx, "        %s: %s\n", exempt->user, exempt->desc);
768   if (dates[0])
769     dprintf(idx, "        %s\n", dates);
770 }
771 
772 /* Take host entry from invite list and display it ban-style. */
display_invite(int idx,int number,maskrec * invite,struct chanset_t * chan,int show_inact)773 static void display_invite(int idx, int number, maskrec *invite,
774                            struct chanset_t *chan, int show_inact)
775 {
776   char dates[81], s[41];
777 
778   if (invite->added) {
779     daysago(now, invite->added, s);
780     sprintf(dates, "%s %s", MODES_CREATED, s);
781     if (invite->added < invite->lastactive) {
782       strcat(dates, ", ");
783       strcat(dates, MODES_LASTUSED);
784       strcat(dates, " ");
785       daysago(now, invite->lastactive, s);
786       strcat(dates, s);
787     }
788   } else
789     dates[0] = 0;
790   if (invite->flags & MASKREC_PERM)
791     strcpy(s, "(expires: never)");
792   else {
793     char s1[41];
794 
795     strftime(s1, 23, "%d.%m.%Y %H:%M:%S", localtime(&invite->expire));
796     sprintf(s, "(expires: %s)", s1);
797   }
798   if (invite->flags & MASKREC_STICKY)
799     strcat(s, " (sticky)");
800   if (!chan || ischaninvite(chan, invite->mask)) {
801     if (number >= 0)
802       dprintf(idx, "  [%3d] %s %s\n", number, invite->mask, s);
803     else
804       dprintf(idx, "INVITE: %s %s\n", invite->mask, s);
805   } else if (show_inact) {
806     if (number >= 0)
807       dprintf(idx, "! [%3d] %s %s\n", number, invite->mask, s);
808     else
809       dprintf(idx, "INVITE (%s): %s %s\n", MODES_INACTIVE, invite->mask, s);
810   } else
811     return;
812   dprintf(idx, "        %s: %s\n", invite->user, invite->desc);
813   if (dates[0])
814     dprintf(idx, "        %s\n", dates);
815 }
816 
tell_bans(int idx,int show_inact,char * match)817 static void tell_bans(int idx, int show_inact, char *match)
818 {
819   int k = 1;
820   char *chname;
821   struct chanset_t *chan = NULL;
822   maskrec *u;
823 
824   if (match[0]) {
825     chname = newsplit(&match);
826     if (chname[0] && (strchr(CHANMETA, chname[0]))) {
827       chan = findchan_by_dname(chname);
828       if (!chan) {
829         dprintf(idx, "%s.\n", CHAN_NOSUCH);
830         return;
831       }
832     } else
833       match = chname;
834   }
835 
836   if (!chan && !(chan = findchan_by_dname(dcc[idx].u.chat->con_chan)) &&
837       !(chan = chanset))
838     chan = NULL;
839 
840   if (chan && show_inact)
841     dprintf(idx, "%s:   (! = %s %s)\n", BANS_GLOBAL,
842             MODES_NOTACTIVE, chan->dname);
843   else
844     dprintf(idx, "%s:\n", BANS_GLOBAL);
845   for (u = global_bans; u; u = u->next) {
846     if (match[0]) {
847       if ((wild_match(match, u->mask)) ||
848           (wild_match(match, u->desc)) || (wild_match(match, u->user)))
849         display_ban(idx, k, u, chan, 1);
850       k++;
851     } else
852       display_ban(idx, k++, u, chan, show_inact);
853   }
854   if (chan) {
855     if (show_inact)
856       dprintf(idx, "%s %s:   (! = %s, * = %s)\n",
857               BANS_BYCHANNEL, chan->dname, MODES_NOTACTIVE2, MODES_NOTBYBOT);
858     else
859       dprintf(idx, "%s %s:  (* = %s)\n",
860               BANS_BYCHANNEL, chan->dname, MODES_NOTBYBOT);
861     for (u = chan->bans; u; u = u->next) {
862       if (match[0]) {
863         if ((wild_match(match, u->mask)) ||
864             (wild_match(match, u->desc)) || (wild_match(match, u->user)))
865           display_ban(idx, k, u, chan, 1);
866         k++;
867       } else
868         display_ban(idx, k++, u, chan, show_inact);
869     }
870     if (chan->status & CHAN_ACTIVE) {
871       masklist *b;
872       char s[UHOSTLEN], *s1, *s2, fill[256];
873       int min, sec;
874 
875       for (b = chan->channel.ban; b && b->mask[0]; b = b->next) {
876         if ((!u_equals_mask(global_bans, b->mask)) &&
877             (!u_equals_mask(chan->bans, b->mask))) {
878           strcpy(s, b->who);
879           s2 = s;
880           s1 = splitnick(&s2);
881           if (s1[0])
882             sprintf(fill, "%s (%s!%s)", b->mask, s1, s2);
883           else
884             sprintf(fill, "%s (server %s)", b->mask, s2);
885           if (b->timer != 0) {
886             min = (now - b->timer) / 60;
887             sec = (now - b->timer) - (min * 60);
888             sprintf(s, " (active %02d:%02d)", min, sec);
889             strcat(fill, s);
890           }
891           if ((!match[0]) || (wild_match(match, b->mask)))
892             dprintf(idx, "* [%3d] %s\n", k, fill);
893           k++;
894         }
895       }
896     }
897   }
898   if (k == 1)
899     dprintf(idx, "(There are no bans, permanent or otherwise.)\n");
900   if ((!show_inact) && (!match[0]))
901     dprintf(idx, "%s.\n", BANS_USEBANSALL);
902 }
903 
tell_exempts(int idx,int show_inact,char * match)904 static void tell_exempts(int idx, int show_inact, char *match)
905 {
906   int k = 1;
907   char *chname;
908   struct chanset_t *chan = NULL;
909   maskrec *u;
910 
911   if (match[0]) {
912     chname = newsplit(&match);
913     if (chname[0] && strchr(CHANMETA, chname[0])) {
914       chan = findchan_by_dname(chname);
915       if (!chan) {
916         dprintf(idx, "%s.\n", CHAN_NOSUCH);
917         return;
918       }
919     } else
920       match = chname;
921   }
922 
923   if (!chan && !(chan = findchan_by_dname(dcc[idx].u.chat->con_chan)) &&
924       !(chan = chanset))
925     chan = NULL;
926 
927   if (chan && show_inact)
928     dprintf(idx, "%s:   (! = %s %s)\n", EXEMPTS_GLOBAL,
929             MODES_NOTACTIVE, chan->dname);
930   else
931     dprintf(idx, "%s:\n", EXEMPTS_GLOBAL);
932   for (u = global_exempts; u; u = u->next) {
933     if (match[0]) {
934       if ((wild_match(match, u->mask)) ||
935           (wild_match(match, u->desc)) || (wild_match(match, u->user)))
936         display_exempt(idx, k, u, chan, 1);
937       k++;
938     } else
939       display_exempt(idx, k++, u, chan, show_inact);
940   }
941   if (chan) {
942     if (show_inact)
943       dprintf(idx, "%s %s:   (! = %s, * = %s)\n", EXEMPTS_BYCHANNEL,
944               chan->dname, MODES_NOTACTIVE2, MODES_NOTBYBOT);
945     else
946       dprintf(idx, "%s %s:  (* = %s)\n",
947               EXEMPTS_BYCHANNEL, chan->dname, MODES_NOTBYBOT);
948     for (u = chan->exempts; u; u = u->next) {
949       if (match[0]) {
950         if ((wild_match(match, u->mask)) ||
951             (wild_match(match, u->desc)) || (wild_match(match, u->user)))
952           display_exempt(idx, k, u, chan, 1);
953         k++;
954       } else
955         display_exempt(idx, k++, u, chan, show_inact);
956     }
957     if (chan->status & CHAN_ACTIVE) {
958       masklist *e;
959       char s[UHOSTLEN], *s1, *s2, fill[256];
960       int min, sec;
961 
962       for (e = chan->channel.exempt; e && e->mask[0]; e = e->next) {
963         if ((!u_equals_mask(global_exempts, e->mask)) &&
964             (!u_equals_mask(chan->exempts, e->mask))) {
965           strcpy(s, e->who);
966           s2 = s;
967           s1 = splitnick(&s2);
968           if (s1[0])
969             sprintf(fill, "%s (%s!%s)", e->mask, s1, s2);
970           else
971             sprintf(fill, "%s (server %s)", e->mask, s2);
972           if (e->timer != 0) {
973             min = (now - e->timer) / 60;
974             sec = (now - e->timer) - (min * 60);
975             sprintf(s, " (active %02d:%02d)", min, sec);
976             strcat(fill, s);
977           }
978           if ((!match[0]) || (wild_match(match, e->mask)))
979             dprintf(idx, "* [%3d] %s\n", k, fill);
980           k++;
981         }
982       }
983     }
984   }
985   if (k == 1)
986     dprintf(idx, "(There are no ban exempts, permanent or otherwise.)\n");
987   if ((!show_inact) && (!match[0]))
988     dprintf(idx, "%s.\n", EXEMPTS_USEEXEMPTSALL);
989 }
990 
tell_invites(int idx,int show_inact,char * match)991 static void tell_invites(int idx, int show_inact, char *match)
992 {
993   int k = 1;
994   char *chname;
995   struct chanset_t *chan = NULL;
996   maskrec *u;
997 
998   if (match[0]) {
999     chname = newsplit(&match);
1000     if (chname[0] && strchr(CHANMETA, chname[0])) {
1001       chan = findchan_by_dname(chname);
1002       if (!chan) {
1003         dprintf(idx, "%s.\n", CHAN_NOSUCH);
1004         return;
1005       }
1006     } else
1007       match = chname;
1008   }
1009 
1010   if (!chan && !(chan = findchan_by_dname(dcc[idx].u.chat->con_chan)) &&
1011       !(chan = chanset))
1012     chan = NULL;
1013 
1014   if (chan && show_inact)
1015     dprintf(idx, "%s:   (! = %s %s)\n", INVITES_GLOBAL,
1016             MODES_NOTACTIVE, chan->dname);
1017   else
1018     dprintf(idx, "%s:\n", INVITES_GLOBAL);
1019   for (u = global_invites; u; u = u->next) {
1020     if (match[0]) {
1021       if ((wild_match(match, u->mask)) ||
1022           (wild_match(match, u->desc)) || (wild_match(match, u->user)))
1023         display_invite(idx, k, u, chan, 1);
1024       k++;
1025     } else
1026       display_invite(idx, k++, u, chan, show_inact);
1027   }
1028   if (chan) {
1029     if (show_inact)
1030       dprintf(idx, "%s %s:   (! = %s, * = %s)\n", INVITES_BYCHANNEL,
1031               chan->dname, MODES_NOTACTIVE2, MODES_NOTBYBOT);
1032     else
1033       dprintf(idx, "%s %s:  (* = %s)\n",
1034               INVITES_BYCHANNEL, chan->dname, MODES_NOTBYBOT);
1035     for (u = chan->invites; u; u = u->next) {
1036       if (match[0]) {
1037         if ((wild_match(match, u->mask)) ||
1038             (wild_match(match, u->desc)) || (wild_match(match, u->user)))
1039           display_invite(idx, k, u, chan, 1);
1040         k++;
1041       } else
1042         display_invite(idx, k++, u, chan, show_inact);
1043     }
1044     if (chan->status & CHAN_ACTIVE) {
1045       masklist *i;
1046       char s[UHOSTLEN], *s1, *s2, fill[256];
1047       int min, sec;
1048 
1049       for (i = chan->channel.invite; i && i->mask[0]; i = i->next) {
1050         if ((!u_equals_mask(global_invites, i->mask)) &&
1051             (!u_equals_mask(chan->invites, i->mask))) {
1052           strcpy(s, i->who);
1053           s2 = s;
1054           s1 = splitnick(&s2);
1055           if (s1[0])
1056             sprintf(fill, "%s (%s!%s)", i->mask, s1, s2);
1057           else
1058             sprintf(fill, "%s (server %s)", i->mask, s2);
1059           if (i->timer != 0) {
1060             min = (now - i->timer) / 60;
1061             sec = (now - i->timer) - (min * 60);
1062             sprintf(s, " (active %02d:%02d)", min, sec);
1063             strcat(fill, s);
1064           }
1065           if ((!match[0]) || (wild_match(match, i->mask)))
1066             dprintf(idx, "* [%3d] %s\n", k, fill);
1067           k++;
1068         }
1069       }
1070     }
1071   }
1072   if (k == 1)
1073     dprintf(idx, "(There are no invites, permanent or otherwise.)\n");
1074   if ((!show_inact) && (!match[0]))
1075     dprintf(idx, "%s.\n", INVITES_USEINVITESALL);
1076 }
1077 
1078 /* Write the ban lists and the ignore list to a file. */
write_bans(FILE * f,int idx,char * key)1079 static int write_bans(FILE *f, int idx, char *key)
1080 {
1081   struct chanset_t *chan;
1082   maskrec *b;
1083   char *mask;
1084 
1085   if (global_bans)
1086     if (efprintf(f, key, BAN_NAME " - -\n") == EOF)
1087       return 0;
1088   for (b = global_bans; b; b = b->next) {
1089     mask = str_escape(b->mask, ':', '\\');
1090     if (!mask ||
1091         efprintf(f, key, "- %s:%s%lu%s:+%lu:%lu:%s:%s\n", mask,
1092                 (b->flags & MASKREC_PERM) ? "+" : "", b->expire,
1093                 (b->flags & MASKREC_STICKY) ? "*" : "", b->added,
1094                 b->lastactive, b->user ? b->user : botnetnick,
1095                 b->desc ? b->desc : "requested") == EOF) {
1096       if (mask)
1097         nfree(mask);
1098       return 0;
1099     }
1100     nfree(mask);
1101   }
1102   for (chan = chanset; chan; chan = chan->next)
1103     if ((idx < 0) || (chan->status & CHAN_SHARED)) {
1104       struct flag_record fr = { FR_CHAN | FR_GLOBAL | FR_BOT, 0, 0, 0, 0, 0 };
1105 
1106       if (idx >= 0)
1107         get_user_flagrec(dcc[idx].user, &fr, chan->dname);
1108       else
1109         fr.chan = BOT_SHARE;
1110       if ((fr.chan & BOT_SHARE) || (fr.bot & BOT_GLOBAL)) {
1111         if (efprintf(f, key, "::%s bans\n", chan->dname) == EOF)
1112           return 0;
1113         for (b = chan->bans; b; b = b->next) {
1114           mask = str_escape(b->mask, ':', '\\');
1115           if (!mask ||
1116               efprintf(f, key, "- %s:%s%lu%s:+%lu:%lu:%s:%s\n", mask,
1117                       (b->flags & MASKREC_PERM) ? "+" : "", b->expire,
1118                       (b->flags & MASKREC_STICKY) ? "*" : "", b->added,
1119                       b->lastactive, b->user ? b->user : botnetnick,
1120                       b->desc ? b->desc : "requested") == EOF) {
1121             if (mask)
1122               nfree(mask);
1123             return 0;
1124           }
1125           nfree(mask);
1126         }
1127       }
1128     }
1129   return 1;
1130 }
1131 
1132 /* Write the exemptlists to a file. */
write_exempts(FILE * f,int idx,char * key)1133 static int write_exempts(FILE *f, int idx, char *key)
1134 {
1135   struct chanset_t *chan;
1136   maskrec *e;
1137   char *mask;
1138 
1139   if (global_exempts)
1140     if (efprintf(f, key, EXEMPT_NAME " - -\n") == EOF)        /* Daemus */
1141       return 0;
1142   for (e = global_exempts; e; e = e->next) {
1143     mask = str_escape(e->mask, ':', '\\');
1144     if (!mask ||
1145         efprintf(f, key, "%s %s:%s%lu%s:+%lu:%lu:%s:%s\n", "%", mask,
1146                 (e->flags & MASKREC_PERM) ? "+" : "", e->expire,
1147                 (e->flags & MASKREC_STICKY) ? "*" : "", e->added,
1148                 e->lastactive, e->user ? e->user : botnetnick,
1149                 e->desc ? e->desc : "requested") == EOF) {
1150       if (mask)
1151         nfree(mask);
1152       return 0;
1153     }
1154     nfree(mask);
1155   }
1156   for (chan = chanset; chan; chan = chan->next)
1157     if ((idx < 0) || (chan->status & CHAN_SHARED)) {
1158       struct flag_record fr = { FR_CHAN | FR_GLOBAL | FR_BOT, 0, 0, 0, 0, 0 };
1159 
1160       if (idx >= 0)
1161         get_user_flagrec(dcc[idx].user, &fr, chan->dname);
1162       else
1163         fr.chan = BOT_SHARE;
1164       if ((fr.chan & BOT_SHARE) || (fr.bot & BOT_GLOBAL)) {
1165         if (efprintf(f, key, "&&%s exempts\n", chan->dname) == EOF)
1166           return 0;
1167         for (e = chan->exempts; e; e = e->next) {
1168           mask = str_escape(e->mask, ':', '\\');
1169           if (!mask ||
1170               efprintf(f, key, "%s %s:%s%lu%s:+%lu:%lu:%s:%s\n", "%", mask,
1171                       (e->flags & MASKREC_PERM) ? "+" : "", e->expire,
1172                       (e->flags & MASKREC_STICKY) ? "*" : "", e->added,
1173                       e->lastactive, e->user ? e->user : botnetnick,
1174                       e->desc ? e->desc : "requested") == EOF) {
1175             if (mask)
1176               nfree(mask);
1177             return 0;
1178           }
1179           nfree(mask);
1180         }
1181       }
1182     }
1183   return 1;
1184 }
1185 
1186 /* Write the invitelists to a file. */
write_invites(FILE * f,int idx,char * key)1187 static int write_invites(FILE *f, int idx, char *key)
1188 {
1189   struct chanset_t *chan;
1190   maskrec *ir;
1191   char *mask;
1192 
1193   if (global_invites)
1194     if (efprintf(f, key, INVITE_NAME " - -\n") == EOF)
1195       return 0;
1196   for (ir = global_invites; ir; ir = ir->next) {
1197     mask = str_escape(ir->mask, ':', '\\');
1198     if (!mask ||
1199         efprintf(f, key, "@ %s:%s%lu%s:+%lu:%lu:%s:%s\n", mask,
1200                 (ir->flags & MASKREC_PERM) ? "+" : "", ir->expire,
1201                 (ir->flags & MASKREC_STICKY) ? "*" : "", ir->added,
1202                 ir->lastactive, ir->user ? ir->user : botnetnick,
1203                 ir->desc ? ir->desc : "requested") == EOF) {
1204       if (mask)
1205         nfree(mask);
1206       return 0;
1207     }
1208     nfree(mask);
1209   }
1210   for (chan = chanset; chan; chan = chan->next)
1211     if ((idx < 0) || (chan->status & CHAN_SHARED)) {
1212       struct flag_record fr = { FR_CHAN | FR_GLOBAL | FR_BOT, 0, 0, 0, 0, 0 };
1213 
1214       if (idx >= 0)
1215         get_user_flagrec(dcc[idx].user, &fr, chan->dname);
1216       else
1217         fr.chan = BOT_SHARE;
1218       if ((fr.chan & BOT_SHARE) || (fr.bot & BOT_GLOBAL)) {
1219         if (efprintf(f, key, "$$%s invites\n", chan->dname) == EOF)
1220           return 0;
1221         for (ir = chan->invites; ir; ir = ir->next) {
1222           mask = str_escape(ir->mask, ':', '\\');
1223           if (!mask ||
1224               efprintf(f, key, "@ %s:%s%lu%s:+%lu:%lu:%s:%s\n", mask,
1225                       (ir->flags & MASKREC_PERM) ? "+" : "", ir->expire,
1226                       (ir->flags & MASKREC_STICKY) ? "*" : "", ir->added,
1227                       ir->lastactive, ir->user ? ir->user : botnetnick,
1228                       ir->desc ? ir->desc : "requested") == EOF) {
1229             if (mask)
1230               nfree(mask);
1231             return 0;
1232           }
1233           nfree(mask);
1234         }
1235       }
1236     }
1237   return 1;
1238 }
1239 
channels_writeuserfile(void)1240 static void channels_writeuserfile(void)
1241 {
1242   char s[1024], key[256] = "-DONTENCRYPTFILES-";
1243   FILE *f;
1244   int ret = 0;
1245 
1246   simple_sprintf(s, "%s~new", userfile);
1247   f = fopen(s, "a");
1248   if (f) {
1249     if (!export_userfile)
1250       strcpy(key, userfileCryptKey);
1251     ret = write_bans(f, -1, key);
1252     ret += write_exempts(f, -1, key);
1253     ret += write_invites(f, -1, key);
1254     fclose(f);
1255   }
1256   if (ret < 3)
1257     putlog(LOG_MISC, "*", USERF_ERRWRITE);
1258   write_channels();
1259 }
1260 
1261 /* Expire mask originally set by `who' on `chan'? */
expired_mask(struct chanset_t * chan,char * who)1262 static int expired_mask(struct chanset_t *chan, char *who)
1263 {
1264   memberlist *m, *m2;
1265   char buf[UHOSTLEN], *snick, *sfrom;
1266   struct userrec *u;
1267 
1268   if (force_expire)
1269     return 1;
1270 
1271   strcpy(buf, who);
1272   sfrom = buf;
1273   snick = splitnick(&sfrom);
1274 
1275   if (!snick[0])
1276     return 1;
1277 
1278   m = ismember(chan, snick);
1279   if (!m)
1280     for (m2 = chan->channel.member; m2 && m2->nick[0]; m2 = m2->next)
1281       if (!EvangelineStrcasecmp(sfrom, m2->userhost)) {
1282         m = m2;
1283         break;
1284       }
1285 
1286   if (!m || !chan_hasop(m) || !rfc_casecmp(m->nick, botname))
1287     return 1;
1288 
1289   if (m->user)
1290     u = m->user;
1291   else {
1292     simple_sprintf(buf, "%s!%s", m->nick, m->userhost);
1293     u = get_user_by_host(buf);
1294   }
1295   if (u && u->flags & USER_BOT)
1296     return 0;
1297   else
1298     return 1;
1299 }
1300 
1301 /* Check for expired timed-bans. */
check_expired_bans(void)1302 static void check_expired_bans(void)
1303 {
1304   maskrec *u, *u2;
1305   struct chanset_t *chan;
1306   masklist *b;
1307 
1308   for (u = global_bans; u; u = u2) {
1309     u2 = u->next;
1310     if (!(u->flags & MASKREC_PERM) && (now >= u->expire)) {
1311       putlog(LOG_MISC, "*", "%s %s (%s)", BANS_NOLONGER, u->mask, MISC_EXPIRED);
1312       for (chan = chanset; chan; chan = chan->next)
1313         for (b = chan->channel.ban; b->mask[0]; b = b->next)
1314           if (!rfc_casecmp(b->mask, u->mask) &&
1315               expired_mask(chan, b->who) && b->timer != now) {
1316             add_mode(chan, '-', 'b', u->mask);
1317             b->timer = now;
1318           }
1319       u_delban(NULL, u->mask, 1);
1320     }
1321   }
1322   for (chan = chanset; chan; chan = chan->next) {
1323     for (u = chan->bans; u; u = u2) {
1324       u2 = u->next;
1325       if (!(u->flags & MASKREC_PERM) && (now >= u->expire)) {
1326         putlog(LOG_MISC, "*", "%s %s %s %s (%s)", BANS_NOLONGER,
1327                u->mask, MISC_ONLOCALE, chan->dname, MISC_EXPIRED);
1328         for (b = chan->channel.ban; b->mask[0]; b = b->next)
1329           if (!rfc_casecmp(b->mask, u->mask) &&
1330               expired_mask(chan, b->who) && b->timer != now) {
1331             add_mode(chan, '-', 'b', u->mask);
1332             b->timer = now;
1333           }
1334         u_delban(chan, u->mask, 1);
1335       }
1336     }
1337   }
1338 }
1339 
1340 /* Check for expired timed-exemptions */
check_expired_exempts(void)1341 static void check_expired_exempts(void)
1342 {
1343   maskrec *u, *u2;
1344   struct chanset_t *chan;
1345   masklist *b, *e;
1346   int match;
1347 
1348   if (!use_exempts)
1349     return;
1350   for (u = global_exempts; u; u = u2) {
1351     u2 = u->next;
1352     if (!(u->flags & MASKREC_PERM) && (now >= u->expire)) {
1353       putlog(LOG_MISC, "*", "%s %s (%s)", EXEMPTS_NOLONGER,
1354              u->mask, MISC_EXPIRED);
1355       for (chan = chanset; chan; chan = chan->next) {
1356         match = 0;
1357         b = chan->channel.ban;
1358         while (b->mask[0] && !match) {
1359           if (wild_match(b->mask, u->mask) || wild_match(u->mask, b->mask))
1360             match = 1;
1361           else
1362             b = b->next;
1363         }
1364         if (match)
1365           putlog(LOG_MISC, chan->dname,
1366                  "Exempt not expired on channel %s. Ban still set!",
1367                  chan->dname);
1368         else
1369           for (e = chan->channel.exempt; e->mask[0]; e = e->next)
1370             if (!rfc_casecmp(e->mask, u->mask) &&
1371                 expired_mask(chan, e->who) && e->timer != now) {
1372               add_mode(chan, '-', 'e', u->mask);
1373               e->timer = now;
1374             }
1375       }
1376       u_delexempt(NULL, u->mask, 1);
1377     }
1378   }
1379   for (chan = chanset; chan; chan = chan->next) {
1380     for (u = chan->exempts; u; u = u2) {
1381       u2 = u->next;
1382       if (!(u->flags & MASKREC_PERM) && (now >= u->expire)) {
1383         match = 0;
1384         b = chan->channel.ban;
1385         while (b->mask[0] && !match) {
1386           if (wild_match(b->mask, u->mask) || wild_match(u->mask, b->mask))
1387             match = 1;
1388           else
1389             b = b->next;
1390         }
1391         if (match)
1392           putlog(LOG_MISC, chan->dname,
1393                  "Exempt not expired on channel %s. Ban still set!",
1394                  chan->dname);
1395         else {
1396           putlog(LOG_MISC, "*", "%s %s %s %s (%s)", EXEMPTS_NOLONGER,
1397                  u->mask, MISC_ONLOCALE, chan->dname, MISC_EXPIRED);
1398           for (e = chan->channel.exempt; e->mask[0]; e = e->next)
1399             if (!rfc_casecmp(e->mask, u->mask) &&
1400                 expired_mask(chan, e->who) && e->timer != now) {
1401               add_mode(chan, '-', 'e', u->mask);
1402               e->timer = now;
1403             }
1404           u_delexempt(chan, u->mask, 1);
1405         }
1406       }
1407     }
1408   }
1409 }
1410 
1411 /* Check for expired timed-invites. */
check_expired_invites(void)1412 static void check_expired_invites(void)
1413 {
1414   maskrec *u, *u2;
1415   struct chanset_t *chan;
1416   masklist *b;
1417 
1418   if (!use_invites)
1419     return;
1420   for (u = global_invites; u; u = u2) {
1421     u2 = u->next;
1422     if (!(u->flags & MASKREC_PERM) && (now >= u->expire)) {
1423       putlog(LOG_MISC, "*", "%s %s (%s)", INVITES_NOLONGER,
1424              u->mask, MISC_EXPIRED);
1425       for (chan = chanset; chan; chan = chan->next)
1426         if (!(chan->channel.mode & CHANINV))
1427           for (b = chan->channel.invite; b->mask[0]; b = b->next)
1428             if (!rfc_casecmp(b->mask, u->mask) &&
1429                 expired_mask(chan, b->who) && b->timer != now) {
1430               add_mode(chan, '-', 'I', u->mask);
1431               b->timer = now;
1432             }
1433       u_delinvite(NULL, u->mask, 1);
1434     }
1435   }
1436   for (chan = chanset; chan; chan = chan->next) {
1437     for (u = chan->invites; u; u = u2) {
1438       u2 = u->next;
1439       if (!(u->flags & MASKREC_PERM) && (now >= u->expire)) {
1440         putlog(LOG_MISC, "*", "%s %s %s %s (%s)", INVITES_NOLONGER,
1441                u->mask, MISC_ONLOCALE, chan->dname, MISC_EXPIRED);
1442         if (!(chan->channel.mode & CHANINV))
1443           for (b = chan->channel.invite; b->mask[0]; b = b->next)
1444             if (!rfc_casecmp(b->mask, u->mask) &&
1445                 expired_mask(chan, b->who) && b->timer != now) {
1446               add_mode(chan, '-', 'I', u->mask);
1447               b->timer = now;
1448             }
1449         u_delinvite(chan, u->mask, 1);
1450       }
1451     }
1452   }
1453 }
1454