/* * counter.c: repeated message counters * * Copyright(c) 1998-2000 - All Rights Reserved * * See the COPYRIGHT file. */ #ifndef lint static char rcsid[] = "@(#)$Id: counter.c,v 1.5 2000/07/31 22:33:55 kalt Exp $"; #endif #include "os.h" #include "struct.h" #include "option.h" #include "term.h" #include "utils.h" #include "window.h" extern struct server_ *server; #if defined(HAVE_REGEXP) struct counter_ { void *reference; char *string; struct server_ *server; regmatch_t pmatch[20]; time_t vfirst, first, last; int tcount, count; char ematch; /* exact matches */ }; static struct counter_ *counters; static unsigned int cnt_max, cnt_inuse = 0; # define CNT_PERIOD 600 # define CNT_EXPIRE 120 #endif void counter_init() { #if defined(HAVE_REGEXP) cnt_max = 100; counters = (struct counter_ *) malloc(cnt_max*sizeof(struct counter_)); bzero(counters, cnt_max*sizeof(struct counter_)); #endif } #if defined(HAVE_REGEXP) /* counter_expire: expires entries in counters array */ void counter_expire(entry) int entry; { if (entry >= 0) { time_t now = time(NULL); if (now - counters[entry].last > CNT_EXPIRE) { free(counters[entry].string); counters[entry].string = NULL; cnt_inuse--; } } else { vsic_slog(LOG_DEBUG, "counter_expire(-1): cnt_inuse = %d / cnt_max = %d", cnt_inuse, cnt_max); for (entry = 0; entry < cnt_max; entry++) if (counters[entry].string != NULL) counter_expire(entry); vsic_slog(LOG_DEBUG, "finished: cnt_inuse = %d / cnt_max = %d", cnt_inuse, cnt_max); } } /* counter_check: is it time to display something? */ static void counter_check(entry) int entry; { time_t now = time(NULL); if (now - counters[entry].first > CNT_PERIOD) { char tbuf[40]; counters[entry].tcount += counters[entry].count; if (counters[entry].vfirst == counters[entry].first) vsic_slog(LOG_CLIENT, "--- Next message repeated %d time%s over last %d seconds.", counters[entry].count, (counters[entry].count > 1) ? "s" : "", counters[entry].last - counters[entry].first); else vsic_slog(LOG_CLIENT, "--- Next message repeated %d time%s over last %d seconds (%d times since %s).", counters[entry].count, (counters[entry].count > 1) ? "s" : "", counters[entry].last - counters[entry].first, counters[entry].tcount, my_cftime(tbuf, 40, "%x %X", counters[entry].vfirst)); counters[entry].count = 0; counters[entry].ematch = 1; } } /* counter_add: count */ int counter_add(ref, string, attributes, pmatch, flags, channel) void *ref; char *string, *channel; char *attributes; regmatch_t *pmatch; unsigned int *flags; { int i, j; for (i = 0; i < cnt_max; i++) { if (counters[i].reference != ref) continue; if (counters[i].string == NULL) continue; for (j = 1; pmatch[j].rm_so != -1; j++) if (counters[i].server == server && !strncasecmp(string + pmatch[j].rm_so, counters[i].string + counters[i].pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so)) break; if (pmatch[j].rm_so != -1) break; } if (i == cnt_max) { for (i = 0; i < cnt_max; i++) if (counters[i].string == NULL) break; if (i == cnt_max) { counters = realloc(counters, sizeof(struct counter_)*(cnt_max += 100)); bzero(counters+cnt_max-100, 100*sizeof(struct counter_)); } cnt_inuse++; counters[i].reference = ref; counters[i].string = strdup(string); counters[i].server = server; counters[i].vfirst = counters[i].first = counters[i].last = time(NULL); bcopy(pmatch, counters[i].pmatch, 20*sizeof(regmatch_t)); counters[i].tcount = counters[i].count = 1; counters[i].ematch = 1; } else { counters[i].last = time(NULL); if (counters[i].count++ == 0) counters[i].first = counters[i].last; if (counters[i].ematch == 1 && strcasecmp(string, counters[i].string)) counters[i].ematch = 0; } j = counters[i].ematch; counter_check(i); if (counters[i].count > 0 && !(counters[i].count == 1 && counters[i].vfirst == counters[i].first)) /* ignore, ** unless do_repeat() just reseted the count (displaying a message), ** or this is the very first message of this kind received. */ *flags |= LOG_IGNORE; if (j == 0 && !(counters[i].count == 1 && counters[i].vfirst == counters[i].first) && get_option(Z_VCOUNT, channel)) { for (j = 1; pmatch[j].rm_so != -1; j++) { char *ch = attributes + pmatch[j].rm_so; while (ch < attributes + pmatch[j].rm_eo) *ch++ |= TERM_UNDERLINE; } return 1; } return 0; } #endif