#define KEY_REASON "reason"
#define KEY_EXPIRES "expires"
+#define KEY_LASTMOD "lastmod"
#define KEY_ISSUER "issuer"
#define KEY_ISSUED "issued"
+#define KEY_LIFETIME "lifetime"
static heap_t gline_heap; /* key: expiry time, data: struct gline_entry* */
static dict_t gline_dict; /* key: target, data: struct gline_entry* */
gline_comparator(const void *a, const void *b)
{
const struct gline *ga=a, *gb=b;
- return ga->expires - gb->expires;
+ return ga->lifetime - gb->lifetime;
}
static void
}
static int
-gline_for_p(UNUSED_ARG(void *key), void *data, void *extra)
+gline_equal_p(UNUSED_ARG(void *key), void *data, void *extra)
{
- struct gline *ge = data;
- return !irccasecmp(ge->target, extra);
-}
-
-static int
-delete_gline_for_p(UNUSED_ARG(void *key), void *data, void *extra)
-{
- struct gline *ge = data;
-
- if (!irccasecmp(ge->target, extra)) {
- free_gline(ge);
- return 1;
- } else {
- return 0;
- }
+ return data == extra;
}
static void
gline_expire(UNUSED_ARG(void *data))
{
- time_t stopped;
+ unsigned long stopped;
void *wraa;
stopped = 0;
while (heap_size(gline_heap)) {
heap_peek(gline_heap, 0, &wraa);
- stopped = ((struct gline*)wraa)->expires;
+ stopped = ((struct gline*)wraa)->lifetime;
if (stopped > now)
break;
heap_pop(gline_heap);
int
gline_remove(const char *target, int announce)
{
- int res = dict_find(gline_dict, target, NULL) ? 1 : 0;
- if (heap_remove_pred(gline_heap, delete_gline_for_p, (char*)target)) {
- void *argh;
- struct gline *new_first;
- heap_peek(gline_heap, 0, &argh);
- if (argh) {
- new_first = argh;
- timeq_del(0, gline_expire, 0, TIMEQ_IGNORE_WHEN|TIMEQ_IGNORE_DATA);
- timeq_add(new_first->expires, gline_expire, 0);
- }
- }
-#ifdef WITH_PROTOCOL_BAHAMUT
- /* Bahamut is sort of lame: It permanently remembers any AKILLs
- * with durations longer than a day, and will never auto-expire
- * them. So when the time comes, we'd better remind it. */
- announce = 1;
-#endif
+ struct gline *gl;
+
+ gl = dict_find(gline_dict, target, NULL);
+ if (gl != NULL)
+ gl->expires = now;
if (announce)
irc_ungline(target);
- return res;
+ return gl != NULL;
}
struct gline *
-gline_add(const char *issuer, const char *target, unsigned long duration, const char *reason, time_t issued, int announce)
+gline_add(const char *issuer, const char *target, unsigned long duration, const char *reason, unsigned long issued, unsigned long lastmod, unsigned long lifetime, int announce)
{
struct gline *ent;
struct gline *prev_first;
void *argh;
+ unsigned long expires;
heap_peek(gline_heap, 0, &argh);
prev_first = argh;
+ expires = now + duration;
+ if (lifetime < expires)
+ lifetime = expires;
ent = dict_find(gline_dict, target, NULL);
if (ent) {
- heap_remove_pred(gline_heap, gline_for_p, (char*)target);
- if (ent->expires < (time_t)(now + duration))
- ent->expires = now + duration;
+ heap_remove_pred(gline_heap, gline_equal_p, ent);
+ if (ent->issued > lastmod)
+ ent->issued = lastmod;
+ if (ent->lastmod < lastmod) {
+ ent->lastmod = lastmod;
+ ent->expires = expires;
+ if (strcmp(ent->reason, reason)) {
+ free(ent->reason);
+ ent->reason = strdup(reason);
+ }
+ }
+ if (ent->lifetime < lifetime)
+ ent->lifetime = lifetime;
} else {
ent = malloc(sizeof(*ent));
ent->issued = issued;
+ ent->lastmod = lastmod;
ent->issuer = strdup(issuer);
ent->target = strdup(target);
- ent->expires = now + duration;
+ ent->expires = expires;
+ ent->lifetime = lifetime;
ent->reason = strdup(reason);
dict_insert(gline_dict, ent->target, ent);
}
heap_insert(gline_heap, ent, ent);
- if (!prev_first || (ent->expires < prev_first->expires)) {
- timeq_del(0, gline_expire, 0, TIMEQ_IGNORE_WHEN|TIMEQ_IGNORE_DATA);
- timeq_add(ent->expires, gline_expire, 0);
+ if (!prev_first || (ent->lifetime < prev_first->lifetime)) {
+ timeq_del(0, gline_expire, 0, TIMEQ_IGNORE_WHEN|TIMEQ_IGNORE_DATA);
+ timeq_add(ent->lifetime, gline_expire, 0);
}
if (announce)
irc_gline(NULL, ent);
gline_alternate_target(const char *target)
{
const char *hostname;
- unsigned long ip;
- char *res;
/* If no host part, bail. */
if (!(hostname = strchr(target, '@')))
/* If host part contains wildcards, bail. */
if (hostname[strcspn(hostname, "*?/")])
return NULL;
- /* If host part looks like an IP, parse it that way. */
- if (!hostname[strspn(hostname+1, "0123456789.")+1]) {
- struct in_addr in;
- struct hostent *he;
- if (inet_aton(hostname+1, &in)
- && (he = gethostbyaddr(&in, sizeof(in), AF_INET))) {
- res = malloc((hostname - target) + 2 + strlen(he->h_name));
- sprintf(res, "%.*s@%s", hostname - target, target, he->h_name);
- return res;
- } else
- return NULL;
- } else if (getipbyname(hostname+1, &ip)) {
- res = malloc((hostname - target) + 18);
- sprintf(res, "%.*s@%lu.%lu.%lu.%lu", hostname - target, target, ip & 255, (ip >> 8) & 255, (ip >> 16) & 255, (ip >> 24) & 255);
- return res;
- } else
- return NULL;
+ /* Get parsed address and canonical name for host. */
+#if 0
+ irc_in_addr_t in; /* move this to the right place */
+ if (irc_pton(&in, NULL, hostname+1)) {
+ if (getnameinfo(/*TODO*/))
+ return NULL;
+ } else if (!getaddrinfo(/*TODO*/)) {
+ } else return NULL;
+#else
+ return NULL;
+#endif
}
struct gline *
{
struct record_data *rd = data;
const char *issuer, *reason, *dstr;
- time_t issued, expiration;
+ unsigned long issued, expiration, lastmod, lifetime;
if (!(reason = database_get_data(rd->d.object, KEY_REASON, RECDB_QSTRING))) {
- log_module(MAIN_LOG, LOG_ERROR, "Missing reason for gline %s", key);
- return 0;
+ log_module(MAIN_LOG, LOG_ERROR, "Missing reason for gline %s", key);
+ return 0;
}
if (!(dstr = database_get_data(rd->d.object, KEY_EXPIRES, RECDB_QSTRING))) {
- log_module(MAIN_LOG, LOG_ERROR, "Missing expiration for gline %s", key);
- return 0;
+ log_module(MAIN_LOG, LOG_ERROR, "Missing expiration for gline %s", key);
+ return 0;
}
expiration = strtoul(dstr, NULL, 0);
- if ((dstr = database_get_data(rd->d.object, KEY_ISSUED, RECDB_QSTRING))) {
- issued = strtoul(dstr, NULL, 0);
- } else {
- issued = now;
- }
- if (!(issuer = database_get_data(rd->d.object, KEY_ISSUER, RECDB_QSTRING))) {
+ dstr = database_get_data(rd->d.object, KEY_LIFETIME, RECDB_QSTRING);
+ lifetime = dstr ? strtoul(dstr, NULL, 0) : expiration;
+ dstr = database_get_data(rd->d.object, KEY_LASTMOD, RECDB_QSTRING);
+ lastmod = dstr ? strtoul(dstr, NULL, 0) : 0;
+ dstr = database_get_data(rd->d.object, KEY_ISSUED, RECDB_QSTRING);
+ issued = dstr ? strtoul(dstr, NULL, 0) : now;
+ if (!(issuer = database_get_data(rd->d.object, KEY_ISSUER, RECDB_QSTRING)))
issuer = "<unknown>";
- }
- if (expiration > now)
- gline_add(issuer, key, expiration - now, reason, issued, 0);
+ if (lifetime > now)
+ gline_add(issuer, key, expiration - now, reason, issued, lastmod, lifetime, 0);
return 0;
}
saxdb_start_record(ctx, ent->target, 0);
saxdb_write_int(ctx, KEY_EXPIRES, ent->expires);
saxdb_write_int(ctx, KEY_ISSUED, ent->issued);
+ saxdb_write_int(ctx, KEY_LIFETIME, ent->lifetime);
+ if (ent->lastmod)
+ saxdb_write_int(ctx, KEY_LASTMOD, ent->lastmod);
saxdb_write_string(ctx, KEY_REASON, ent->reason);
saxdb_write_string(ctx, KEY_ISSUER, ent->issuer);
saxdb_end_record(ctx);
struct gline_discrim *discrim;
discrim = calloc(1, sizeof(*discrim));
- discrim->max_issued = now;
discrim->limit = 50;
+ discrim->max_issued = ULONG_MAX;
+ discrim->max_lastmod = ULONG_MAX;
+ discrim->max_lifetime = ULONG_MAX;
for (i=0; i<argc; i++) {
if (i + 2 > argc) {
discrim->min_expire = now + ParseInterval(argv[++i]);
else if (!irccasecmp(argv[i], "before"))
discrim->max_issued = now - ParseInterval(argv[++i]);
- else {
+ else if (!irccasecmp(argv[i], "lastmod")) {
+ const char *cmp = argv[++i];
+ if (cmp[0] == '<') {
+ if (cmp[1] == '=') {
+ discrim->min_lastmod = now - ParseInterval(cmp + 2);
+ } else {
+ discrim->min_lastmod = now - (ParseInterval(cmp + 1) - 1);
+ }
+ } else if (cmp[0] == '>') {
+ if (cmp[1] == '=') {
+ discrim->max_lastmod = now - ParseInterval(cmp + 2);
+ } else {
+ discrim->max_lastmod = now - (ParseInterval(cmp + 1) - 1);
+ }
+ } else {
+ discrim->min_lastmod = now - ParseInterval(cmp + 2);
+ }
+ } else if (!irccasecmp(argv[i], "lifetime")) {
+ const char *cmp = argv[++i];
+ if (cmp[0] == '<') {
+ if (cmp[1] == '=') {
+ discrim->min_lifetime = now - ParseInterval(cmp + 2);
+ } else {
+ discrim->min_lifetime = now - (ParseInterval(cmp + 1) - 1);
+ }
+ } else if (cmp[0] == '>') {
+ if (cmp[1] == '=') {
+ discrim->max_lifetime = now - ParseInterval(cmp + 2);
+ } else {
+ discrim->max_lifetime = now - (ParseInterval(cmp + 1) - 1);
+ }
+ } else {
+ discrim->min_lifetime = now - ParseInterval(cmp + 2);
+ }
+ } else {
send_message(user, src, "MSG_INVALID_CRITERIA", argv[i]);
goto fail;
}
&& (!discrim->alt_target_mask
|| !match_ircglobs(discrim->alt_target_mask, gline->target)))))
|| (discrim->max_issued < gline->issued)
- || (discrim->min_expire > gline->expires)) {
+ || (discrim->min_expire > gline->expires)
+ || (discrim->min_lastmod > gline->lastmod)
+ || (discrim->max_lastmod < gline->lastmod)
+ || (discrim->min_lifetime > gline->lifetime)
+ || (discrim->max_lifetime < gline->lifetime)) {
return 0;
}
return 1;