Convert time-related variables to consistently use "unsigned long".
[srvx.git] / src / gline.c
index 318791991f63afd686ed8fa2d6d155957e9aeb91..3ca7e1a682760be649f126eb2dfb236a21cd30f3 100644 (file)
@@ -40,6 +40,7 @@
 
 #define KEY_REASON "reason"
 #define KEY_EXPIRES "expires"
+#define KEY_LASTMOD "lastmod"
 #define KEY_ISSUER "issuer"
 #define KEY_ISSUED "issued"
 
@@ -92,7 +93,7 @@ delete_gline_for_p(UNUSED_ARG(void *key), void *data, void *extra)
 static void
 gline_expire(UNUSED_ARG(void *data))
 {
-    time_t stopped;
+    unsigned long stopped;
     void *wraa;
 
     stopped = 0;
@@ -134,7 +135,7 @@ gline_remove(const char *target, int announce)
 }
 
 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, int announce)
 {
     struct gline *ent;
     struct gline *prev_first;
@@ -145,11 +146,14 @@ gline_add(const char *issuer, const char *target, unsigned long duration, const
     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))
+        if (ent->expires < now + duration)
             ent->expires = now + duration;
+        if (ent->lastmod < lastmod)
+            ent->lastmod = lastmod;
     } else {
         ent = malloc(sizeof(*ent));
         ent->issued = issued;
+        ent->lastmod = lastmod;
         ent->issuer = strdup(issuer);
         ent->target = strdup(target);
         ent->expires = now + duration;
@@ -158,8 +162,8 @@ gline_add(const char *issuer, const char *target, unsigned long duration, const
     }
     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);
+        timeq_del(0, gline_expire, 0, TIMEQ_IGNORE_WHEN|TIMEQ_IGNORE_DATA);
+        timeq_add(ent->expires, gline_expire, 0);
     }
     if (announce)
         irc_gline(NULL, ent);
@@ -170,8 +174,6 @@ static char *
 gline_alternate_target(const char *target)
 {
     const char *hostname;
-    unsigned long ip;
-    char *res;
 
     /* If no host part, bail. */
     if (!(hostname = strchr(target, '@')))
@@ -179,23 +181,17 @@ gline_alternate_target(const char *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 *
@@ -259,17 +255,19 @@ gline_add_record(const char *key, void *data, UNUSED_ARG(void *extra))
 {
     struct record_data *rd = data;
     const char *issuer, *reason, *dstr;
-    time_t issued, expiration;
+    unsigned long issued, expiration, lastmod;
 
     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);
+    dstr = database_get_data(rd->d.object, KEY_LASTMOD, RECDB_QSTRING);
+    lastmod = dstr ? strtoul(dstr, NULL, 0) : 0;
     if ((dstr = database_get_data(rd->d.object, KEY_ISSUED, RECDB_QSTRING))) {
         issued = strtoul(dstr, NULL, 0);
     } else {
@@ -279,7 +277,7 @@ gline_add_record(const char *key, void *data, UNUSED_ARG(void *extra))
         issuer = "<unknown>";
     }
     if (expiration > now)
-        gline_add(issuer, key, expiration - now, reason, issued, 0);
+        gline_add(issuer, key, expiration - now, reason, issued, lastmod, 0);
     return 0;
 }
 
@@ -298,6 +296,8 @@ gline_write_entry(UNUSED_ARG(void *key), void *data, void *extra)
     saxdb_start_record(ctx, ent->target, 0);
     saxdb_write_int(ctx, KEY_EXPIRES, ent->expires);
     saxdb_write_int(ctx, KEY_ISSUED, ent->issued);
+    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);
@@ -335,8 +335,9 @@ gline_discrim_create(struct userNode *user, struct userNode *src, unsigned int a
     struct gline_discrim *discrim;
 
     discrim = calloc(1, sizeof(*discrim));
-    discrim->max_issued = now;
     discrim->limit = 50;
+    discrim->max_issued = INT_MAX;
+    discrim->max_lastmod = INT_MAX;
 
     for (i=0; i<argc; i++) {
         if (i + 2 > argc) {
@@ -371,7 +372,24 @@ gline_discrim_create(struct userNode *user, struct userNode *src, unsigned int a
             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 {
             send_message(user, src, "MSG_INVALID_CRITERIA", argv[i]);
             goto fail;
         }
@@ -409,7 +427,9 @@ gline_discrim_match(struct gline *gline, struct gline_discrim *discrim)
                     && (!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)) {
         return 0;
     }
     return 1;