diff --git a/sensors/slothd/GNUmakefile.in b/sensors/slothd/GNUmakefile.in
index c6228fcb709b5353260804e614f6301b9dbec064..79ae0c34d060e13d8191be0309b0da2b519e6cd5 100644
--- a/sensors/slothd/GNUmakefile.in
+++ b/sensors/slothd/GNUmakefile.in
@@ -8,8 +8,10 @@ SRCDIR          = @srcdir@
 TESTBED_SRCDIR  = @top_srcdir@
 OBJDIR          = ../..
 SUBDIR          = sensors/slothd
+SLOTHD_DIR	= unknownclient
 
 SBIN_SCRIPTS    = sdisrunning sddeploy
+SDPROGS		= sdcollectd slothd
 
 include $(OBJDIR)/Makeconf
 
@@ -21,17 +23,19 @@ SDLIBS+= -ltb -lmysqlclient
 LIBS=
 CP= cp -pf
 
-PROGS= slothd sdcollectd
+SYSTEM  := $(shell uname -s)
 
-all: $(PROGS)
+all: $(SDPROGS) client
 
 include ${TESTBED_SRCDIR}/GNUmakerules
 
-linux: islinux slothd
-	$(CP) slothd linux/slothd
+ifeq ($(SYSTEM),Linux)
+SLOTHD_DIR	= linuxclient
+endif
 
-fbsd: isfbsd slothd
-	$(CP) slothd fbsd/slothd
+ifeq ($(SYSTEM),FreeBSD)
+SLOTHD_DIR	= fbsdclient
+endif
 
 slothd: slothd.o slothd.h version.o
 	$(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ slothd.o version.o $(LIBS)
@@ -42,14 +46,15 @@ sdcollectd: sdcollectd.o sdcollectd.h version.o
 version.c: slothd.c slothd.h sdcollectd.c sdcollectd.h
 	echo >$@ "char build_info[] = \"Built `date +%d-%b-%Y` by `id -nu`@`hostname | sed 's/\..*//'`:`pwd`\";"
 
-islinux:
-	@uname -s | grep inux > /dev/null
+client: slothd
+	-mkdir $(SLOTHD_DIR)
+	$(CP) slothd $(SLOTHD_DIR)/slothd
 
-isfbsd:
-	@uname -s | grep BSD > /dev/null
+install: $(addprefix $(INSTALL_SBINDIR)/, $(SBIN_SCRIPTS) sdcollectd)
 
-install: $(addprefix $(INSTALL_SBINDIR)/, $(SBIN_SCRIPTS))
+client-install:
+	$(INSTALL_PROGRAM) $(SLOTHD_DIR)/slothd $(DESTDIR)$(CLIENT_BINDIR)
 
 clean:
-	rm -f *.o $(PROGS) *~ core *.core version.c
+	rm -f *.o $(SDPROGS) *~ core *.core version.c
 
diff --git a/sensors/slothd/sdcollectd.c b/sensors/slothd/sdcollectd.c
index 830fc777b6dcf1478f2ca3ec0e8b50ae2f1f6cd6..de617a1bed1510e09a4f6e8f73c5534e7dae86df 100644
--- a/sensors/slothd/sdcollectd.c
+++ b/sensors/slothd/sdcollectd.c
@@ -29,11 +29,13 @@ void siginthandler(int signum) {
 
 void usage(void) {  
 
-  printf("Usage:\tslothd -h\n");
-  printf("\tslothd [-d] [-p <port>]\n");
-  printf("\t -h\t This message.\n");
-  printf("\t -d\t Debug mode; do not fork into background.\n");
-  printf("\t -p <port>\t Send on port <port> (default is %d).\n", SDCOLLECTD_PORT);
+  printf("Usage:\tslothd -h\n"
+         "\tslothd [-d] [-p <port>]\n"
+         "\t -h\t This message.\n"
+         "\t -o\t DO populate old idlestats tables.\n"
+         "\t -d\t Debug mode; do not fork into background.\n"
+         "\t -p <port>\t Listen on port <port> (default is %d).\n", 
+         SDCOLLECTD_PORT);
 }
 
 
@@ -42,12 +44,18 @@ int parse_args(int argc, char **argv) {
   char ch;
 
   /* setup defaults. */
+  opts->popold = 0;
   opts->debug = 0;
   opts->port = SDCOLLECTD_PORT;
 
-  while ((ch = getopt(argc, argv, "dp:h")) != -1) {
+  while ((ch = getopt(argc, argv, "odp:h")) != -1) {
     switch (ch) {
 
+    case 'o':
+      lnotice("Populating old node_idlestats, and iface_counters tables");
+      opts->popold = 1;
+      break;
+
     case 'd':
       lnotice("Debug mode requested; staying in foreground.\n");
       opts->debug = 1;
@@ -80,20 +88,20 @@ int main(int argc, char **argv) {
   extern char build_info[];
 
   opts = &gopts;
-
+  
   /* Foo on SIGPIPE & SIGHUP. */
   signal(SIGPIPE, SIG_IGN);
   signal(SIGHUP, SIG_IGN);
-
+  
   /* Cleanup on sigint/term */
   signal(SIGTERM, siginthandler);
   signal(SIGINT, siginthandler);
-
+  
   if (!parse_args(argc, argv)) {
     lnotice("Error processing arguments, exiting.\n");
     exit(1);
   }
-
+  
   /* clear, and initialize inet sockaddr */
   bzero(&servaddr, sizeof(struct sockaddr_in));
   servaddr.sin_family = AF_INET;
@@ -140,8 +148,9 @@ int main(int argc, char **argv) {
   for ( ;; ) {
     bzero(&iddata, sizeof(IDLE_DATA)); /* cleanse out old values, if any */
     if (CollectData(sd, &iddata)) {
-      ParseRecord(&iddata);
-      PutDBRecord(&iddata);
+      if (ParseRecord(&iddata)) {
+        PutDBRecord(&iddata);
+      }
     }
   }
   /* NOTREACHED */
@@ -149,6 +158,7 @@ int main(int argc, char **argv) {
 
 int CollectData(int sd, IDLE_DATA *iddata) {
   int numbytes, slen;
+  time_t curtime;
   /* struct hostent *hent; */
   struct sockaddr_in cliaddr;
 
@@ -157,20 +167,14 @@ int CollectData(int sd, IDLE_DATA *iddata) {
 
   if((numbytes = recvfrom(sd, iddata->buf, sizeof(iddata->buf), 0,
                           (struct sockaddr*)&cliaddr, &slen))) {
-    /* Using libtb functionality now.
-      if (!(hent = gethostbyaddr((char*)&cliaddr.sin_addr, 
-      sizeof(cliaddr.sin_addr), AF_INET))) {
-      lerror("Can't resolve host");
-      return -1;
-    }
-    */
 
     if (!mydb_iptonodeid(inet_ntoa(cliaddr.sin_addr), iddata->id)) {
       lerror("Couldn't obtain node id");
       return 0;
     }
     if (opts->debug) {
-      printf("Received data from: %s\n", iddata->id);
+      curtime = time(NULL);
+      printf("Received data from: %s at %s\n", iddata->id, ctime(&curtime));
       printf("buffer: %s\n", iddata->buf);
     }
   }
@@ -246,50 +250,57 @@ char *tbmac(char *maddr, char **endptr) {
   }
 }
 
-void ParseRecord(IDLE_DATA *iddata) {
 
-  int i;
-  char *itemptr, *ptr;
+int ParseRecord(IDLE_DATA *iddata) {
+
+  int tmpvers;
+  char *itemptr, *ptr, *tmpstr;
 
   iddata->ifcnt = 0;
   
   /* Parse out fields */
   itemptr = strtok(iddata->buf, " \t");
   do {
-    if (strstr(itemptr, "mis")) {
+
+    if (strstr(itemptr, "vers")) {
+      if ((tmpvers = strtoul(itemptr+5, NULL, 10)) > SDPROTOVERS) {
+        lerror("Unsupported protocol version; rejecting.");
+        return 0;
+      }
+      iddata->version = tmpvers;
+    }
+
+    else if (strstr(itemptr, "mis")) {
       iddata->mis = atol(itemptr+4);
     }
+
     else if (strstr(itemptr, "lave")) {
       iddata->l1m = strtod(itemptr+5, &ptr);
       iddata->l5m = strtod(ptr+1, &ptr);
       iddata->l15m = strtod(ptr+1, NULL);
     }
+
     else if (strstr(itemptr, "iface")) {
-      strcpy(iddata->ifaces[iddata->ifcnt].mac, tbmac(itemptr+6, &ptr));
+      if (!(tmpstr = tbmac(itemptr+6, &ptr))) {
+        lerror("Malformed interface record encountered, skipping");
+        continue;
+      }
+      strcpy(iddata->ifaces[iddata->ifcnt].mac, tmpstr);
       iddata->ifaces[iddata->ifcnt].ipkts = strtoul(ptr+1, &ptr, 10);
       iddata->ifaces[iddata->ifcnt].opkts = strtoul(ptr+1, NULL, 10);
       iddata->ifcnt++;
     }
+
+    else if (strstr(itemptr, "abits")) {
+      iddata->actbits = strtoul(itemptr+6, NULL, 16);
+    }
+
     else {
       lnotice("Unrecognized string in packet\n");
     }
   } while ((itemptr = strtok(NULL, " \t")) && iddata->ifcnt < MAXNUMIFACES);
 
-  if (opts->debug) {
-    printf("iddata->mis: %lu\n", iddata->mis);
-    printf("iddata->l1m: %f\n", iddata->l1m);
-    printf("iddata->l5m: %f\n", iddata->l5m);
-    printf("iddata->l15m: %f\n", iddata->l15m);
-    for (i = 0; i < iddata->ifcnt; ++i) {
-      printf("iface%d: %s, ipkts %lu, opkts %lu\n",
-             i,
-             iddata->ifaces[i].mac,
-             iddata->ifaces[i].ipkts,
-             iddata->ifaces[i].opkts);
-    }
-  }
-
-  return;
+  return 1;
 }
 
 
@@ -297,26 +308,77 @@ void PutDBRecord(IDLE_DATA *iddata) {
 
   int i;
   time_t now = time(NULL);
+  char curstamp[100];
+  char tmpstr[(NUMACTTYPES+1)*sizeof(curstamp)];
+  char *actstr[] = ACTSTRARRAY;
 
-  if (!mydb_update("INSERT INTO node_idlestats VALUES ('%s', FROM_UNIXTIME(%lu), FROM_UNIXTIME(%lu),  %f, %f, %f)", 
-                   iddata->id, 
-                   now,
-                   iddata->mis, 
-                   iddata->l1m, 
-                   iddata->l5m, 
-                   iddata->l15m)) {
-    lerror("Error inserting data into node_idlestats table");
-  }
+  sprintf(curstamp, "FROM_UNIXTIME(%lu)", now);
 
-  for (i = 0; i < iddata->ifcnt; ++i) {
-    if (!mydb_update("INSERT INTO iface_counters VALUES ('%s', FROM_UNIXTIME(%lu), '%s', %lu, %lu)",
-                     iddata->id,
+  printf("now: %s\n", ctime(&now));
+
+  if (opts->debug) {
+    printf("\nReceived and parsed packet. Contents:\n"
+           "Version: %u\n"
+           "Node: %s\n"
+           "Last TTY: %s"
+           "Load averages (1, 5, 15): %f, %f, %f\n"
+           "Active bits: 0x%04x\n",
+           iddata->version,
+           iddata->id,
+           ctime(&iddata->mis),
+           iddata->l1m,
+           iddata->l5m,
+           iddata->l15m,
+           iddata->actbits);
+    for (i = 0; i < iddata->ifcnt; ++i) {
+      printf("Interface %s: ipkts: %lu  opkts: %lu\n",
+             iddata->ifaces[i].mac,
+             iddata->ifaces[i].ipkts,
+             iddata->ifaces[i].opkts);
+    }
+    printf("\n\n");
+  }
+  
+  if (opts->popold) {
+    if (!mydb_update("INSERT INTO node_idlestats VALUES ('%s', FROM_UNIXTIME(%lu), FROM_UNIXTIME(%lu), %f, %f, %f)", 
+                     iddata->id, 
                      now,
-                     iddata->ifaces[i].mac,
-                     iddata->ifaces[i].ipkts,
-                     iddata->ifaces[i].opkts)) {
-      lerror("Error inserting data into iface_counters table");
+                     iddata->mis, 
+                     iddata->l1m, 
+                     iddata->l5m, 
+                     iddata->l15m)) {
+      lerror("Error inserting data into node_idlestats table");
+    }
+    
+    for (i = 0; i < iddata->ifcnt; ++i) {
+      if (!mydb_update("INSERT INTO iface_counters VALUES ('%s', FROM_UNIXTIME(%lu), '%s', %lu, %lu)",
+                       iddata->id,
+                       now,
+                       iddata->ifaces[i].mac,
+                       iddata->ifaces[i].ipkts,
+                       iddata->ifaces[i].opkts)) {
+        lerror("Error inserting data into iface_counters table");
+      }
     }
   }
+  
+  if (iddata->version >= 2) {
+    sprintf(tmpstr, "last_report=%s", curstamp);
+    for (i = 0; i < NUMACTTYPES; ++i) {
+      if (iddata->actbits & (1<<i)) {
+          sprintf(tmpstr, "%s, %s=%s",
+                  tmpstr,
+                  actstr[i], 
+                  curstamp);
+      }
+    }
+
+    if(!mydb_update("UPDATE node_activity SET %s WHERE node_id = '%s'",
+                    tmpstr,
+                    iddata->id)) {
+      lerror("Error updating stamps in node_activity table");
+    }
+  }
+
   return;
 }
diff --git a/sensors/slothd/sdcollectd.h b/sensors/slothd/sdcollectd.h
index 53ec4b6a3e21246f073092a94348415dad6afeb1..c761023587a7ae2f21273a9439d82fc48b1003f8 100644
--- a/sensors/slothd/sdcollectd.h
+++ b/sensors/slothd/sdcollectd.h
@@ -26,13 +26,18 @@
 #include <syslog.h>
 #include <tbdb.h>
 
+#define SDPROTOVERS 2
 #define SDCOLLECTD_PORT 8509
 #define NODENAMESIZE 100
 #define BUFSIZE 1500
 #define MAXNUMIFACES 10
 #define MACADDRLEN 12
 
+#define NUMACTTYPES 4
+#define ACTSTRARRAY {"last_tty_act", "last_cpu_act", "last_net_act", "last_ext_act"}
+
 typedef struct {
+  u_char popold;
   u_char debug;
   u_short port;
 } SDCOLLECTD_OPTS;
@@ -40,24 +45,26 @@ typedef struct {
 SDCOLLECTD_OPTS *opts;
 
 typedef struct {
-  long mis;
+  long   mis;
   double l1m;
   double l5m;
   double l15m;
   u_char ifcnt;
+  u_int  actbits;
+  u_int  version;
   struct {
     char mac[MACADDRLEN+1];
     long ipkts;
     long opkts;
-  } ifaces[MAXNUMIFACES];
-  char id[NODENAMESIZE];      /* Host identifier - probably local part of hostname */
-  char buf[BUFSIZE];    /* String containing monitor output values */
+  }      ifaces[MAXNUMIFACES];
+  char   id[NODENAMESIZE];      /* Host identifier - probably local part of hostname */
+  char   buf[BUFSIZE];    /* String containing monitor output values */
 } IDLE_DATA;
 
 extern int errno;
 
 int CollectData(int, IDLE_DATA*);
-void ParseRecord(IDLE_DATA*);
+int ParseRecord(IDLE_DATA*);
 void PutDBRecord(IDLE_DATA*);
 
 char *tbmac(char*, char**);
diff --git a/sensors/slothd/slothd.c b/sensors/slothd/slothd.c
index ab649986905cc32811e8546686c289bd6a99e95c..845a1368b523b1f2c8def1181d3d8070e1abb589 100644
--- a/sensors/slothd/slothd.c
+++ b/sensors/slothd/slothd.c
@@ -6,8 +6,8 @@
 
 #include "slothd.h"
 
-SLOTHD_PACKET *pkt;
 SLOTHD_OPTS   *opts;
+SLOTHD_PARAMS *parms;
 
 void lerror(const char* msgstr) {
   if (msgstr) {
@@ -42,42 +42,53 @@ void sigunkhandler(int signum) {
 }
 
 void siginthandler(int signum) {
-
-  int status;
-
-  unlink(PIDFILE);
-  while (wait(&status) != -1);
-  lnotice("exiting.");
-  exit(0);
+  parms->dolast = 1;
+  signal(SIGTERM, siginthandler);
+  signal(SIGINT, siginthandler);
+  signal(SIGQUIT, siginthandler);
 }
 
 void usage(void) {  
 
-  printf("Usage:\tslothd -h\n");
-  printf("\tslothd [-a] [-d] [-i <interval>] [-p <port>] [-s <server>]\n");
-  printf("\t -h\t This message.\n");
-  printf("\t -a\t Only scan active terminal special files.\n");
-  printf("\t -f\t Do not send idle data report immediately on startup.\n");
-  printf("\t -d\t Debug mode; do not fork into background.\n");
-  printf("\t -i <interval>\t Run interval, in seconds. (default is 10 min.)\n");
-  printf("\t -p <port>\t Send on port <port> (default is %d).\n", SLOTHD_DEF_PORT);
-  printf("\t -s <server>\t Send data to <server> (default is %s).\n", SLOTHD_DEF_SERV);
+  printf("Usage:\tslothd -h\n"
+         "\tslothd [-o] [-a] [-d] [-i <interval>] [-p <port>] [-s <server>]\n"
+         "\t       [-g <interval>] [-l <thresh>] [-c <thresh>]\n"
+         "\t -h\t\t This message.\n"
+         "\t -o\t\t Run once (collect a single report).\n"
+         "\t -a\t\t Only scan active terminal special files.\n"
+         "\t -d\t\t Debug mode; do not fork into background.\n"
+         "\t -i <interval>\t Regular run interval, in seconds.\n"
+         "\t -g <interval>\t Aggressive run interval, in seconds.\n"
+         "\t -l <thresh>\t load threshold (default 1 @ 1 minute).\n"
+         "\t -c <thresh>\t experimental network packet difference threshold (pps).\n"
+         "\t -n <thresh>\t control network packet difference threshold (pps)\n"
+         "\t -p <port>\t Send on port <port>\n"
+         "\t -s <server>\t Send data to <server>\n");
 }
 
 
 int main(int argc, char **argv) {
 
   int exitcode = -1;
+  u_int myabits, span;
+  time_t curtime;
   static SLOTHD_OPTS mopts;
+  static SLOTHD_PARAMS mparms;
   static SLOTHD_PACKET mpkt;
+  static SLOTHD_PACKET mopkt;
+  SLOTHD_PACKET *pkt, *opkt, *tmppkt;
 
   extern char build_info[];
 
   /* pre-init */
   bzero(&mopts, sizeof(SLOTHD_OPTS));
+  bzero(&mparms, sizeof(SLOTHD_PARAMS));
   bzero(&mpkt, sizeof(SLOTHD_PACKET));
+  bzero(&mopkt, sizeof(SLOTHD_PACKET));
   opts = &mopts;
+  parms = &mparms;
   pkt = &mpkt;
+  opkt = &mopkt;
 
   if (parse_args(argc, argv) < 0) {
     fprintf(stderr, "Error processing arguments.\n");
@@ -91,19 +102,63 @@ int main(int argc, char **argv) {
       lnotice("Slothd started");
       lnotice(build_info);
       for (;;) {
-        if (!opts->first) {
-          sleep(mopts.interval);
+        
+        /* Collect current machine stats */
+        mparms.cnt++;
+        get_load(pkt);
+        get_min_tty_idle(pkt);
+        get_packet_counts(pkt);
+        myabits = get_active_bits(pkt,opkt);
+
+        /*
+         * Time to send a packet?
+         * Yes, if:
+         * 1) We've been idle, and now we see activity (aggressive mode)
+         * 2) Its been over <reg_interval> seconds since the last report
+         */
+        if ((!opkt->actbits && pkt->actbits) ||
+            (time(&curtime) >=  mparms.lastrpt + mopts.reg_interval) ||
+            parms->dolast) {
+          if (send_pkt(pkt)) {
+            mparms.lastrpt = curtime;
+          }
+          if (parms->dolast) {
+            do_exit();
+          }
+          tmppkt = pkt;
+          pkt = opkt;
+          opkt = tmppkt;
         }
-        get_load();
-        get_min_tty_idle();
-        get_packet_counts();
-        send_pkt();
-        if (opts->once) {
+
+        if (mopts.once) {
           break;
         }
-        if (opts->first) {
-            sleep(mopts.interval);
+
+        /* 
+         * Figure out, based on run count, and activity, how long
+         * to sleep.
+         */
+        if (mparms.cnt == 1) {
+          span = mopts.reg_interval - 
+            (rand() / (float) RAND_MAX) * (OFFSET_FRACTION*mopts.reg_interval);
+        }
+        else if (myabits) {
+          span = mopts.reg_interval;
+        }
+        else {
+          span = mopts.agg_interval;
+        }
+        
+        if (opts->debug) {
+          printf("About to sleep for %u seconds.\n", span);
+          fflush(stdout);
         }
+
+        if (parms->dolast) {
+          continue;
+        }
+
+        sleep(span);
       }
     }
   }
@@ -115,15 +170,17 @@ int parse_args(int argc, char **argv) {
   char ch;
 
   /* setup defaults. */
+  opts->once = 0;
+  opts->reg_interval = DEF_RINTVL;
+  opts->agg_interval = DEF_AINTVL;
   opts->debug = 0;
-  opts->actterms = 0;
-  opts->interval = DEF_INTVL;
   opts->port = SLOTHD_DEF_PORT;
   opts->servname = SLOTHD_DEF_SERV;
-  opts->first = 1;
-  opts->once = 0;
+  opts->load_thresh = DEF_LTHRSH;
+  opts->pkt_thresh = DEF_CTHRSH;
+  opts->cif_thresh = DEF_CTHRSH;
 
-  while ((ch = getopt(argc, argv, "ai:dp:s:hfo")) != -1) {
+  while ((ch = getopt(argc, argv, "oi:g:dp:s:l:c:n:h")) != -1) {
     switch (ch) {
 
     case 'o': /* run once */
@@ -131,9 +188,16 @@ int parse_args(int argc, char **argv) {
       break;
 
     case 'i':
-      if ((opts->interval = atoi(optarg)) < MIN_INTVL) {
-        lwarn("Warning!  Interval set too low, defaulting.");
-        opts->interval = MIN_INTVL;
+      if ((opts->reg_interval = atol(optarg)) < MIN_RINTVL) {
+        lwarn("Warning!  Regular interval set too low, defaulting.");
+        opts->reg_interval = MIN_RINTVL;
+      }
+      break;
+
+    case 'g':
+      if ((opts->agg_interval = atol(optarg)) < MIN_AINTVL) {
+        lwarn("Warning! Aggressive interval set too low, defaulting.");
+        opts->reg_interval = MIN_AINTVL;
       }
       break;
 
@@ -142,15 +206,6 @@ int parse_args(int argc, char **argv) {
       opts->debug = 1;
       break;
 
-    case 'a':
-      lnotice("Scanning only active terminals.");
-      opts->actterms = 1;
-      break;
-
-    case 'f':
-      opts->first = 0;
-      break;
-
     case 'p':
       opts->port = (u_short)atoi(optarg);
       break;
@@ -163,6 +218,27 @@ int parse_args(int argc, char **argv) {
         lwarn("Invalid server name, default used.");
       }
       break;
+
+    case 'l':
+      if ((opts->load_thresh = atof(optarg)) < MIN_LTHRSH) {
+        lwarn("Warning! Load threshold set too low, defaulting.");
+        opts->load_thresh = DEF_LTHRSH;
+      }
+      break;
+
+    case 'c':
+      if ((opts->pkt_thresh = atol(optarg)) < MIN_CTHRSH) {
+        lwarn("Warning! Experimental net packet diff threshold too low, defaulting.");
+        opts->pkt_thresh = DEF_CTHRSH;
+      }
+      break;
+
+    case 'n':
+      if ((opts->cif_thresh = atol(optarg)) < MIN_CTHRSH) {
+        lwarn("Warning! Control net packet diff threshold too low, defaulting.");
+        opts->cif_thresh = DEF_CTHRSH;
+      }
+      break;
       
     case 'h':
     default:
@@ -177,15 +253,20 @@ int parse_args(int argc, char **argv) {
 
 int init_slothd(void) {
 
-  DIR *devs;
+DIR *devs;
   int pfd;
   char pidbuf[10];
   char bufstr[MAXDEVLEN];
   struct dirent *dptr;
   struct hostent *hent;
+  char *ciprog[] = {"control_interface", NULL};
 
   /* init internal vars */
-  opts->numttys = 0;
+  parms->dolast = 0;  /* init send-last-report-before-exiting variable */
+  parms->numttys = 0; /* will enum terms in this func */
+  parms->cnt = 0;     /* daemon iter count */
+  parms->lastrpt = 0; /* the last time a report pkt was sent */
+  parms->startup = time(NULL); /* Make sure we don't report < invocation */
 
   /* Setup signals */
   signal(SIGTERM, siginthandler);
@@ -207,39 +288,47 @@ int init_slothd(void) {
     lerror("Couldn't set path env");
   }
 
-  /* enum tty special files, if necessary. */
-  if (!opts->actterms) {
-    if ((devs = opendir("/dev")) == 0) {
-      lerror("Can't open directory /dev for processing");
-      return -1;
-    }
-    opts->ttys[opts->numttys] = strdup("/dev/console");
-    opts->numttys++;
+  /* Seed the random number generator */
+  srand(time(NULL));
+
+  /* Grab control net iface */
+  if (procpipe(ciprog, &grab_cifname, parms)) {
+    lwarn("Failed to get control net iface name");
+  }
+
+#ifdef __linux__
+  /* Open socket for SIOCGHWADDR ioctl (to get mac addresses) */
+  parms->ifd = socket(PF_INET, SOCK_DGRAM, 0);
+#endif
+
+  /* enum tty special files */
+  if ((devs = opendir("/dev")) == 0) {
+    lerror("Can't open directory /dev for processing");
+    return -1;
+  }
+  parms->ttys[parms->numttys] = strdup("/dev/console");
+  parms->numttys++;
 #ifdef __linux__  
-    /* 
-       Include the pts mux device to check for activity on
-       dynamically allocated linux pts devices:
-       (/dev/pts/<num>)
-    */
-    opts->ttys[opts->numttys] = strdup("/dev/ptmx");
-    opts->numttys++;
-
-    /* Open socket for SIOCGHWADDR ioctl */
-    pkt->ifd = socket(PF_INET, SOCK_DGRAM, 0);
+  /* 
+     Include the pts mux device to check for activity on
+     dynamically allocated linux pts devices:
+     (/dev/pts/<num>)
+  */
+  parms->ttys[parms->numttys] = strdup("/dev/ptmx");
+  parms->numttys++;
 #endif
-    while (opts->numttys < MAXTTYS && (dptr = readdir(devs))) {
-      if (strstr(dptr->d_name, "tty") || strstr(dptr->d_name, "pty")) {
-        snprintf(bufstr, MAXDEVLEN, "/dev/%s", dptr->d_name);
-        opts->ttys[opts->numttys] = strdup(bufstr);
-        opts->numttys++;
-        bzero(bufstr, sizeof(bufstr));
-      }
+  while (parms->numttys < MAXTTYS && (dptr = readdir(devs))) {
+    if (strstr(dptr->d_name, "tty") || strstr(dptr->d_name, "pty")) {
+      snprintf(bufstr, MAXDEVLEN, "/dev/%s", dptr->d_name);
+      parms->ttys[parms->numttys] = strdup(bufstr);
+      parms->numttys++;
+      bzero(bufstr, sizeof(bufstr));
     }
   }
   closedir(devs);
 
   /* prepare UDP connection to server */
-  if ((pkt->sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+  if ((parms->sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
     lerror("Could not alloc socket");
     return -1;
   }
@@ -247,12 +336,12 @@ int init_slothd(void) {
     lerror("Can't resolve server hostname"); /* XXX use herror */
     return -1;
   }
-  bzero(&pkt->servaddr, sizeof(struct sockaddr_in));
-  pkt->servaddr.sin_family = AF_INET;
-  pkt->servaddr.sin_port = htons(opts->port);
-  bcopy(hent->h_addr_list[0], &pkt->servaddr.sin_addr.s_addr, 
+  bzero(&parms->servaddr, sizeof(struct sockaddr_in));
+  parms->servaddr.sin_family = AF_INET;
+  parms->servaddr.sin_port = htons(opts->port);
+  bcopy(hent->h_addr_list[0], &parms->servaddr.sin_addr.s_addr, 
         sizeof(struct in_addr));
-  if (connect(pkt->sd, (struct sockaddr*)&pkt->servaddr, 
+  if (connect(parms->sd, (struct sockaddr*)&parms->servaddr, 
               sizeof(struct sockaddr_in)) < 0) {
     lerror("Couldn't connect to server");
     return -1;
@@ -278,56 +367,98 @@ int init_slothd(void) {
 }
 
 
-void get_min_tty_idle(void) {
-  
-  int i;
-  time_t mintime = 0;
-  struct stat sb;
+void do_exit(void) {
+  int status;
 
-  if (opts->actterms) {
-    utmp_enum_terms();
-    if (!opts->numttys) {
-      mintime = wtmp_get_last();
-    }
+  unlink(PIDFILE);
+  while (wait(&status) != -1);
+  lnotice("exiting.");
+  exit(0);
+}
+
+int grab_cifname(char *buf, void *data) {
+
+  int retval = -1;
+  char *tmpptr;
+  SLOTHD_PARAMS *myparms = (SLOTHD_PARAMS*) data;
+
+  if (buf && isalpha(buf[0])) {
+    tmpptr = myparms->cifname = strdup(buf);
+    while (isalnum(*tmpptr))  tmpptr++;
+    *tmpptr = '\0';
+    retval = 0;
+  }
+  else {
+    myparms->cifname = NULL;
   }
 
-#ifdef COMMENT
-  /* Linux uses dynamically allocated UNIX98 ptys */
+  return retval;
+}
+
+
+int send_pkt(SLOTHD_PACKET *pkt) {
+
+  int i, numsent, retval = 1;
+  static char pktbuf[1500];
+  static char minibuf[50];
+
+  /* flatten data into packet buffer */
+  sprintf(pktbuf, "vers=%s mis=%lu lave=%.10f,%.10f,%.10f abits=0x%x ",
+          SDPROTOVERS,
+          pkt->minidle,
+          pkt->loadavg[0],
+          pkt->loadavg[1],
+          pkt->loadavg[2],
+          pkt->actbits);
+  
+  /* get all the interfaces too */
+  for (i = 0; i < pkt->ifcnt; ++i) {
+    sprintf(minibuf, "iface=%s,%lu,%lu ",
+            pkt->ifaces[i].addr,
+            pkt->ifaces[i].ipkts,
+            pkt->ifaces[i].opkts);
+    strcat(pktbuf, minibuf);
+  }
+  
+  if (opts->debug) {
+    printf("packet: %s\n", pktbuf);
+  }
+  
+  /* send it */
   else {
-    DIR *ptsdir;
-    struct dirent *dptr;
-    char *ptspath = "/dev/pts", curpath[15];
-    
-    if ((ptsdir = opendir(ptspath)) == NULL) {
-      lerror("Couldn't open /dev/pts for processing");
+    if ((numsent = send(parms->sd, pktbuf, strlen(pktbuf)+1, 0)) < 0) {
+      lerror("Problem sending slothd packet");
+      retval = 0;
     }
-    else {
-      while ((dptr = readdir(ptsdir))) {
-        sprintf(curpath, "%s/%s", ptspath, dptr->d_name);
-        if (stat(curpath, &sb) < 0) {
-          fprintf(stderr, "Can't stat %s:  %s\n", 
-                  curpath, strerror(errno)); /* XXX change. */
-        }
-        else if (sb.st_atime > mintime) {
-          mintime = sb.st_atime;
-        }
-      }
-      closedir(ptsdir);
+    
+    else if (numsent < strlen(pktbuf)+1) {
+      lwarn("Warning!  Slothd packet truncated");
+      retval = 0;
     }
   }
-#endif /* __linux__ */
 
-  for (i = 0; i < opts->numttys; ++i) {
-    if (stat(opts->ttys[i], &sb) < 0) {
+  return retval;
+}
+
+
+void get_min_tty_idle(SLOTHD_PACKET *pkt) {
+  
+  int i;
+  time_t mintime = 0;
+  struct stat sb;
+
+  for (i = 0; i < parms->numttys; ++i) {
+    if (stat(parms->ttys[i], &sb) < 0) {
       fprintf(stderr, "Can't stat %s:  %s\n", 
-              opts->ttys[i], strerror(errno)); /* XXX change. */
+              parms->ttys[i], strerror(errno)); /* XXX change. */
     }
     else if (sb.st_atime > mintime) {
       mintime = sb.st_atime;
     }
   }
 
-  pkt->minidle = mintime;
+  /* Assign TTY activity, ensuring we don't go older than initial startup */
+  pkt->minidle = (mintime > parms->startup) ? mintime : parms->startup;
   if (opts->debug) {
     printf("Minidle: %s", ctime(&mintime));
   }
@@ -335,90 +466,80 @@ void get_min_tty_idle(void) {
 }
 
 
-void utmp_enum_terms(void) {
-  
-  int utfd, nbytes, i;
-  char bufstr[MAXDEVLEN];
-  struct utmp u;
-
-  for (i = 0; i < opts->numttys; ++i) {
-    free(opts->ttys[i]);
-  }
+void get_load(SLOTHD_PACKET *pkt) {
 
-  opts->numttys = 0;
+  int retval;
 
-  if ((utfd = open(UTMP_PATH, O_RDONLY)) < 0) {
-    lerror("Couldn't open utmp file");
-    return;
+  if ((retval = getloadavg(pkt->loadavg, 3)) < 0 || retval < 3) {
+    lerror("unable to obtain load averages");
+    pkt->loadavg[0] = pkt->loadavg[1] = pkt->loadavg[2] = -1;
   }
-  else {
-    while ((nbytes = read(utfd, &u, sizeof(struct utmp)))) {
-      if (nbytes < sizeof(struct utmp)) {
-        lwarn("problem reading utmp structure - truncated.");
-      }
-      else if (u.ut_name[0] != '\0' && u.ut_host[0] != '\0') {
-        snprintf(bufstr, MAXDEVLEN, "/dev/%s", u.ut_line);
-        opts->ttys[opts->numttys] = strdup(bufstr);
-        opts->numttys++;
-      }
-    }
+  else if (opts->debug) {
+    printf("load averages: %f, %f, %f\n", pkt->loadavg[0], pkt->loadavg[1], 
+           pkt->loadavg[2]);
   }
-
-  close(utfd);
   return;
 }
 
 
-time_t wtmp_get_last(void) {
-  int nbytes;
-  time_t retval = 0;
-  struct utmp u;
-  FILE *wtf;
+int get_active_bits(SLOTHD_PACKET *pkt, SLOTHD_PACKET *opkt) {
 
-  if ((wtf = fopen(WTMP_PATH, "r")) < 0) {
-    lerror("Couldn't open wtmp file");
-  }
+  int i;
 
-  else if (fseek(wtf, -sizeof(struct utmp), SEEK_END) < 0) {
-    lerror("Can't seek to end of file");
-  }
+  pkt->actbits = 0;
 
+  if (pkt->minidle > opkt->minidle) {
+    pkt->actbits |= TTYACT;
+  }
   else {
-    do {
-      nbytes = fread(&u, 1, sizeof(struct utmp), wtf);
-      if (nbytes < sizeof(struct utmp)) {
-        lwarn("problem reading utmp structure - truncated.");
-      }
-      else if (u.ut_name[0] != '\0' &&
-               u.ut_host[0] != '\0' &&
-               strlen(u.ut_line) > 1) {
-        retval = u.ut_time;
-        break;
-      } 
-    } while (fseek(wtf, -2*sizeof(struct utmp), SEEK_CUR) == 0 &&
-             !ferror(wtf));
+    pkt->actbits &= ~TTYACT;
   }
-  fclose(wtf);
-  return retval;
-}        
 
-void get_load(void) {
+  /* XXX: whats the best way to compare load averages to a threshold? */
+  if (pkt->loadavg[0] > opts->load_thresh) {
+    pkt->actbits |= LOADACT;
+  }
+  else {
+    pkt->actbits &= ~LOADACT;
+  }
 
-  int retval;
+  /* 
+   * Have the packet counters exceeded the threshold?  Make sure we don't
+   * count the incoming packets on the control net interface.
+   */
+  for (i = 0; i < pkt->ifcnt; ++i) {
+    if (strcmp(parms->cifname, pkt->ifaces[i].ifname) == 0) {
+      if ((pkt->ifaces[i].opkts - opkt->ifaces[i].opkts) >= 
+          opts->cif_thresh) {
+        break;
+      }
+    }
+    else if (((pkt->ifaces[i].opkts - opkt->ifaces[i].opkts) >= 
+              opts->pkt_thresh) || 
+             ((pkt->ifaces[i].ipkts - opkt->ifaces[i].ipkts) >= 
+              opts->pkt_thresh)) {
+      break;
+    }
+  }
 
-  if ((retval = getloadavg(pkt->loadavg, 3)) < 0 || retval < 3) {
-    lerror("unable to obtain load averages");
-    pkt->loadavg[0] = pkt->loadavg[1] = pkt->loadavg[2] = -1;
+  if (i < pkt->ifcnt) {
+    pkt->actbits |= PKTACT;
+    if (opts->debug) {
+      printf ("Packet threshold exceeded on %s\n", pkt->ifaces[i].ifname);
+    }
   }
-  else if (opts->debug) {
-    printf("load averages: %f, %f, %f\n", pkt->loadavg[0], pkt->loadavg[1], 
-           pkt->loadavg[2]);
+  else {
+    pkt->actbits &= ~PKTACT;
+  }
+
+  if (opts->debug) {
+    printf("Active bits: 0x%04x\n", pkt->actbits);
   }
-  return;
-}
 
+  return pkt->actbits;
+}
 
-void get_packet_counts(void) {
+void get_packet_counts(SLOTHD_PACKET *pkt) {
 
   int i;
   char *niprog[] = {"netstat", "-ni", NULL};
@@ -469,7 +590,7 @@ int get_counters(char *buf, void *data) {
     }
 #ifdef __linux__
     strcpy(ifr.ifr_name, pkt->ifaces[pkt->ifcnt].ifname);
-    if (ioctl(pkt->ifd, SIOCGIFHWADDR, &ifr) < 0) {
+    if (ioctl(parms->ifd, SIOCGIFHWADDR, &ifr) < 0) {
       perror("error getting HWADDR");
       return -1;
     }
@@ -534,42 +655,3 @@ int procpipe(char *const prog[], int (procfunc)(char*,void*), void* data) {
   }
   return retcode;
 }
-  
-
-void send_pkt(void) {
-
-  int i, numsent;
-  static char pktbuf[1500];
-  static char minibuf[50];
-
-  /* flatten data into packet buffer */
-  sprintf(pktbuf, "mis=%lu lave=%.10f,%.10f,%.10f ",
-          pkt->minidle,
-          pkt->loadavg[0],
-          pkt->loadavg[1],
-          pkt->loadavg[2]);
-
-  for (i = 0; i < pkt->ifcnt; ++i) {
-    sprintf(minibuf, "iface=%s,%lu,%lu ",
-            pkt->ifaces[i].addr,
-            pkt->ifaces[i].ipkts,
-            pkt->ifaces[i].opkts);
-    strcat(pktbuf, minibuf);
-  }
-
-  if (opts->debug) {
-    printf("packet: %s\n", pktbuf);
-  }
-
-  /* send it */
-  else {
-    if ((numsent = send(pkt->sd, pktbuf, strlen(pktbuf)+1, 0)) < 0) {
-      lerror("Problem sending slothd packet");
-    }
-
-    else if (numsent < strlen(pktbuf)+1) {
-      lwarn("Warning!  Slothd packet truncated");
-    }
-  }
-  return;
-}
diff --git a/sensors/slothd/slothd.h b/sensors/slothd/slothd.h
index 4c8fb6588143840bd39e38bae7f4de87c3bca1a6..78da01bf9471754a50a044b194986f3e6200aa72 100644
--- a/sensors/slothd/slothd.h
+++ b/sensors/slothd/slothd.h
@@ -20,6 +20,7 @@
 #include <time.h>
 #include <fcntl.h>
 #include <stdio.h>
+#include <ctype.h>
 #include <syslog.h>
 #include <string.h>
 #include <dirent.h>
@@ -37,6 +38,8 @@
 #include <sys/ioctl.h>
 #endif
 
+#define SDPROTOVERS "2"
+
 #define SLOTHD_PATH_ENV "/bin:/usr/bin:/sbin:/usr/sbin:" CLIENT_BINDIR
 #define UTMP_PATH "/var/run/utmp"
 #define WTMP_PATH "/var/log/wtmp"
@@ -47,8 +50,15 @@
 #define LINEBUFLEN 256
 #define MAXTTYS 2000
 #define MAXDEVLEN 50
-#define MIN_INTVL 1
-#define DEF_INTVL 3600  /* 1 hour */
+#define MIN_RINTVL 1     /* 1 minute */
+#define DEF_RINTVL 3600  /* 1 hour */
+#define MIN_AINTVL 1     /* 1 second */
+#define DEF_AINTVL 10    /* 10 seconds */
+#define MIN_LTHRSH 0.1   /* Load avg. threshold */
+#define DEF_LTHRSH 1     /* Fairly high - could get false pos/neg */
+#define MIN_CTHRSH 0     /* No packets */
+#define DEF_CTHRSH 1     /* At least 1 packet */
+#define OFFSET_FRACTION 0.5
 
 #define SLOTHD_DEF_SERV "boss"
 #define SLOTHD_DEF_PORT 8509 /* XXX change */
@@ -63,15 +73,30 @@
 #define NUMSCAN 3
 #endif
 
+#define TTYACT  (1<<0)
+#define LOADACT (1<<1)
+#define PKTACT  (1<<2)
+
 typedef struct {
-  u_long minidle;
-  double loadavg[3];
-  int ifcnt;
   int sd;
 #ifdef __linux__
   int ifd; /* IOCTL file descriptor */
 #endif
+  u_int cnt;
+  char *cifname;
+  u_char dolast;
+  time_t lastrpt;
+  time_t startup;
   struct sockaddr_in servaddr;
+  u_short numttys;
+  char *ttys[MAXTTYS];
+} SLOTHD_PARAMS;
+
+typedef struct {
+  int ifcnt;
+  u_long minidle;
+  double loadavg[3];
+  u_short actbits;
   struct {
     u_long ipkts;
     u_long opkts;
@@ -81,30 +106,29 @@ typedef struct {
 } SLOTHD_PACKET;
 
 typedef struct {
-  u_int interval;
-  u_short numttys;
+  time_t reg_interval;
+  time_t agg_interval;
+  double load_thresh;
+  u_long pkt_thresh;
+  u_long cif_thresh;
   u_char debug;
-  u_char actterms;
-  u_char first;
   u_char once;
   char *servname;
   u_short port;
-  char *ttys[MAXTTYS];
 } SLOTHD_OPTS;
 
 int parse_args(int, char**);
 int init_slothd(void);
+void do_exit(void);
+int send_pkt(SLOTHD_PACKET*);
+int procpipe(char *const prog[], int (procfunc)(char*,void*), void* data);
 
-void get_min_tty_idle(void);
-void utmp_enum_terms(void);
-time_t wtmp_get_last(void);
-void get_load(void);
-void get_packet_counts(void);
+void get_min_tty_idle(SLOTHD_PACKET*);
+void get_load(SLOTHD_PACKET*);
+void get_packet_counts(SLOTHD_PACKET*);
+int get_active_bits(SLOTHD_PACKET*, SLOTHD_PACKET*);
 
-int get_macaddrs(char*,void*);
 int get_counters(char*,void*);
-
-int procpipe(char *const prog[], int (procfunc)(char*,void*), void* data);
-void send_pkt(void);
+int grab_cifname(char*,void*);
 
 #endif /* #ifndef _SLOTHD_H */