]> jfr.im git - irc/quakenet/newserv.git/blobdiff - nickwatch/nickwatch.c
TRUSTS: require sqlite
[irc/quakenet/newserv.git] / nickwatch / nickwatch.c
index d8e38bf6b21305c65143209189d8552b489a46d9..b3e4497bbdda6f8e18889817f79bd202186dd4cb 100644 (file)
@@ -2,15 +2,22 @@
 #include <stdio.h>
 #include <string.h>
 #include "../core/schedule.h"
+#include "../lib/irc_string.h"
+#include "../lib/splitline.h"
 #include "../control/control.h"
 #include "../newsearch/newsearch.h"
 #include "../newsearch/parser.h"
 
+#define NW_FORMAT_TIME "%d/%m/%y %H:%M GMT"
+#define NW_DURATION_MAX (60*60*24*7) // 7 days
+
 typedef struct nickwatch {
   int id;
 
   char createdby[64];
   int hits;
+  time_t lastactive;
+  time_t expiry;
   char term[512];
   parsertree *tree;
 
@@ -32,13 +39,31 @@ static void nw_dummywall(int level, char *format, ...) { }
 static nickwatch *nw_currentwatch;
 static array nw_pendingnicks;
 
+static int nw_nickunwatch(int id) {
+  nickwatch **pnext, *nw;
+
+  for (pnext = &nickwatches; *pnext; pnext = &((*pnext)->next)) {
+    nw = *pnext;
+
+    if (nw->id == id) {
+      parse_free(nw->tree);
+      *pnext = nw->next;
+      free(nw);
+      return 0;
+    }
+  }
+
+  return 1;
+}
+
 static void nw_printnick(searchCtx *ctx, nick *sender, nick *np) {
-  char hostbuf[HOSTLEN+NICKLEN+USERLEN+4];
+  char hostbuf[HOSTLEN+NICKLEN+USERLEN+4], modebuf[34];
   char events[512];
   nickwatchevent *nwe = np->exts[nickwatchext];
   int len;
 
   nw_currentwatch->hits++;
+  nw_currentwatch->lastactive = time(NULL);
 
   events[0] = '\0';
   len = 0;
@@ -50,8 +75,10 @@ static void nw_printnick(searchCtx *ctx, nick *sender, nick *np) {
     len += snprintf(events + len, sizeof(events) - len, "%s", nwe->description);
   }
 
+  strncpy(modebuf, printflags(np->umodes, umodeflags), sizeof(modebuf));
+
   controlwall(NO_OPER, NL_HITS, "nickwatch(#%d, %s): %s [%s] (%s) (%s)", nw_currentwatch->id, events, visiblehostmask(np,hostbuf),
-               IPtostr(np->ipaddress), printflags(np->umodes, umodeflags), np->realname->name->content);
+               IPtostr(np->ipaddress), modebuf, np->realname->name->content);
 }
 
 static void nwe_enqueue(nick *np, const char *format, ...) {
@@ -84,11 +111,12 @@ static void nwe_clear(nick *np) {
 }
 
 static void nw_sched_processevents(void *arg) {
-  nickwatch *nw;
+  nickwatch *nw, *next;
   int i, slot;
   unsigned int marker;
   nick *np;
   array nicks;
+  time_t now = time(NULL);
 
   array_init(&nicks, sizeof(nick *));
   marker = nextnickmarker();
@@ -109,9 +137,14 @@ static void nw_sched_processevents(void *arg) {
   array_free(&nw_pendingnicks);
   array_init(&nw_pendingnicks, sizeof(nick *));
 
-  for (nw = nickwatches; nw; nw = nw->next) {
+  for (nw = nickwatches; nw; nw = next) {
     nw_currentwatch = nw;
+    next = nw->next;
     ast_nicksearch(nw->tree->root, &nw_dummyreply, mynick, &nw_dummywall, &nw_printnick, NULL, NULL, 10, &nicks);
+    if (nw->expiry && nw->expiry <= now) {
+      controlwall(NO_OPER, NL_HITS, "nickwatch(#%d) by %s expired (%d hits): %s", nw->id, nw->createdby, nw->hits, nw->term);
+      nw_nickunwatch(nw->id);
+    }
   }
 
   for (i = 0; i < nicks.cursi; i++) {
@@ -177,13 +210,34 @@ static int nw_cmd_nickwatch(void *source, int cargc, char **cargv) {
   nick *sender = source;
   nickwatch *nw;
   parsertree *tree;
+  time_t duration = NW_DURATION_MAX;
+  size_t i;
+
+  for (i = 0; i < cargc && cargv[i][0] == '-'; i++) {
+    switch (cargv[i][1]) {
+      case 'd':
+        if (++i == cargc)
+          return CMD_USAGE;
+        duration = durationtolong(cargv[i]);
+        if (!duration || duration > NW_DURATION_MAX) {
+          controlreply(sender, "Invalid duration. Maximum: %s.", longtoduration(NW_DURATION_MAX, 1));
+          return CMD_ERROR;
+        }
+        break;
+      default:
+        return CMD_USAGE;
+    }
+  }
 
-  if (cargc < 1)
+  if (i == cargc)
     return CMD_USAGE;
 
-  tree = parse_string(reg_nicksearch, cargv[0]);
+  if (i < (cargc - 1))
+    rejoinline(cargv[i],cargc-i);
+
+  tree = parse_string(reg_nicksearch, cargv[i]);
   if (!tree) {
-    displaystrerror(controlreply, sender, cargv[0]);
+    displaystrerror(controlreply, sender, cargv[i]);
     return CMD_ERROR;
   }
 
@@ -191,8 +245,10 @@ static int nw_cmd_nickwatch(void *source, int cargc, char **cargv) {
   nw->id = nextnickwatch++;
   snprintf(nw->createdby, sizeof(nw->createdby), "#%s", sender->authname);
   nw->hits = 0;
-  strncpy(nw->term, cargv[0], sizeof(nw->term));
-  nw->tree = parse_string(reg_nicksearch, cargv[0]);
+  nw->lastactive = 0;
+  nw->expiry = duration + time(NULL);
+  strncpy(nw->term, cargv[i], sizeof(nw->term));
+  nw->tree = tree;
   nw->next = nickwatches;
   nickwatches = nw;
 
@@ -203,7 +259,6 @@ static int nw_cmd_nickwatch(void *source, int cargc, char **cargv) {
 
 static int nw_cmd_nickunwatch(void *source, int cargc, char **cargv) {
   nick *sender = source;
-  nickwatch **pnext, *nw;
   int id;
 
   if (cargc < 1)
@@ -211,32 +266,35 @@ static int nw_cmd_nickunwatch(void *source, int cargc, char **cargv) {
 
   id = atoi(cargv[0]);
 
-  for (pnext = &nickwatches; *pnext; pnext = &((*pnext)->next)) {
-    nw = *pnext;
-
-    if (nw->id == id) {
-      parse_free(nw->tree);
-      *pnext = nw->next;
-      free(nw);
-
-      controlreply(sender, "Done.");
-      return CMD_OK;
-    }
+  if (nw_nickunwatch(id)) {
+    controlreply(sender, "Nickwatch #%d not found.", id);
+    return CMD_ERROR;
   }
 
-  controlreply(sender, "Nickwatch #%d not found.", id);
+  controlreply(sender, "Done.");
+  return CMD_OK;
+}
 
-  return CMD_ERROR;
+static void nw_formattime(time_t time, char *buf, size_t bufsize) {
+  if (time == 0)
+    strncpy(buf, "(never)", bufsize);
+  else
+    strftime(buf, bufsize, NW_FORMAT_TIME, gmtime(&time));
 }
 
+
 static int nw_cmd_nickwatches(void *source, int cargc, char **cargv) {
   nick *sender = source;
   nickwatch *nw;
+  char timebuf1[20], timebuf2[20];
 
-  controlreply(sender, "ID    Created By      Hits    Term");
+  controlreply(sender, "ID    Created By      Hits    Expires            Last active        Term");
 
-  for (nw = nickwatches; nw; nw = nw->next)
-    controlreply(sender, "%-5d %-15s %-7d %s", nw->id, nw->createdby, nw->hits, nw->term);
+  for (nw = nickwatches; nw; nw = nw->next) {
+    nw_formattime(nw->expiry, timebuf1, sizeof(timebuf1));
+    nw_formattime(nw->lastactive, timebuf2, sizeof(timebuf2));
+    controlreply(sender, "%-5d %-15s %-7d %-18s %-18s %s", nw->id, nw->createdby, nw->hits, timebuf1, timebuf2, nw->term);
+  }
 
   controlreply(sender, "--- End of nickwatches.");
 
@@ -248,7 +306,7 @@ void _init(void) {
 
   array_init(&nw_pendingnicks, sizeof(nick *));
 
-  registercontrolhelpcmd("nickwatch", NO_OPER, 1, &nw_cmd_nickwatch, "Usage: nickwatch <nicksearch term>\nAdds a nickwatch entry.");
+  registercontrolhelpcmd("nickwatch", NO_OPER, 3, &nw_cmd_nickwatch, "Usage: nickwatch ?-d <duration (e.g. 12h5m)>? <nicksearch term>\nAdds a nickwatch entry.");
   registercontrolhelpcmd("nickunwatch", NO_OPER, 1, &nw_cmd_nickunwatch, "Usage: nickunwatch <#id>\nRemoves a nickwatch entry.");
   registercontrolhelpcmd("nickwatches", NO_OPER, 0, &nw_cmd_nickwatches, "Usage: nickwatches\nLists nickwatches.");