URI: 
       Keep track of posted links. - annna - Annna the nice friendly bot.
  HTML git clone git://bitreich.org/annna/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/annna/
   DIR Log
   DIR Files
   DIR Refs
   DIR Tags
   DIR README
       ---
   DIR commit 484cc7bd51ceaaed82b650154cff6bb7e14a878d
   DIR parent 87850ff5e5fe1150688b7c725974d5383a3e496f
  HTML Author: Troels Henriksen <athas@sigkill.dk>
       Date:   Mon,  7 Aug 2023 21:51:25 +0200
       
       Keep track of posted links.
       
       Signed-off-by: Annna Robert-Houdin <annna@bitreich.org>
       
       Diffstat:
         M annna-message-common                |       5 +++++
         A modules/linkbrother/linkbrother.c   |     177 +++++++++++++++++++++++++++++++
         A modules/linkbrother/linkbrother.sh  |      12 ++++++++++++
       
       3 files changed, 194 insertions(+), 0 deletions(-)
       ---
   DIR diff --git a/annna-message-common b/annna-message-common
       @@ -240,6 +240,11 @@ case "${text}" in
                ;;
        esac
        
       +critique=$($modbase/linkbrother/linkbrother.sh "$modbase/linkbrother/db" "$user" "$text")
       +if [ "$critique" ]; then
       +    annna-say -s "${server}" -c "${channel}" "$critique"
       +fi
       +
        case "${text}" in
        "${ircuser}"?)
                exclamation="$(printf "%s\n" "${text}" | sed "s,${ircuser}\(.\),\1,g")"
   DIR diff --git a/modules/linkbrother/linkbrother.c b/modules/linkbrother/linkbrother.c
       @@ -0,0 +1,177 @@
       +// cc linkbrother.c -o linkbrother
       +//
       +// Use: ./linkbrother LINKSFILE USER MESSAGE
       +
       +#define _GNU_SOURCE // sorry
       +
       +#include <stdlib.h>
       +#include <stdio.h>
       +#include <string.h>
       +#include <ctype.h>
       +#include <sys/types.h>
       +#include <sys/stat.h>
       +#include <sys/mman.h>
       +#include <sys/time.h>
       +#include <unistd.h>
       +#include <fcntl.h>
       +#include <time.h>
       +#include <assert.h>
       +
       +FILE* linksf;
       +char* links;
       +int linkslength;
       +time_t now;
       +int userlength;
       +
       +void checklink(const char* user, const char* link) {
       +  int l = strlen(link);
       +  char* foundlink = (char*)memmem(links, linkslength, link, l);
       +  if (foundlink != NULL) {
       +    char* end = foundlink;
       +    while (!isspace(*end) && *end != 0) {
       +      end++;
       +    }
       +    end = 0;
       +    if (*(foundlink + l) == ' ') {
       +      char* nstart = foundlink + l + 1;
       +      char* whostart = strstr(nstart + 1, " ") + 1;
       +      char* whoend = strstr(whostart, "\n");
       +      time_t then = atoi(nstart);
       +      *whoend = 0;
       +
       +      time_t diff = now - then;
       +      char* unit;
       +      int unit_number;
       +
       +      if (diff < 60) {
       +        if (diff == 1) {
       +          unit = "second";
       +        } else {
       +          unit = "seconds";
       +        }
       +        unit_number = diff;
       +      } else if (diff < 60 * 60) {
       +        unit_number = diff / 60;
       +        if (unit_number == 1) {
       +          unit = "minute";
       +        } else {
       +          unit = "minutes";
       +        }
       +      } else if (diff < 60 * 60 * 24) {
       +        unit_number = diff / 60 / 60;
       +        if (unit_number == 1) {
       +          unit = "hour";
       +        } else {
       +          unit = "hours";
       +        }
       +      } else if (diff < 60 * 60 * 24 * 365) {
       +        unit_number = diff / 60 / 60 / 24;
       +        if (unit_number == 1) {
       +          unit = "day";
       +        } else {
       +          unit = "days";
       +        }
       +      } else {
       +        unit_number = diff / 60 / 60 / 24 / 365;
       +        unit = "year";
       +      }
       +
       +      if (strcmp(user, whostart) == 0) {
       +        switch (rand()%3) {
       +        case 0:
       +          printf("%s: You first posted that link %d %s ago!\n",
       +                 user, unit_number, unit);
       +          break;
       +        case 1:
       +          printf("%s: We heard you the first time (%d %s ago).\n",
       +                 user, unit_number, unit);
       +          break;
       +        case 2:
       +          printf("%s: %d %s ago you posted something similar.  How about something new?\n",
       +                 user, unit_number, unit);
       +          break;
       +        }
       +      } else {
       +        switch (rand()%3) {
       +        case 0:
       +          printf("%s: %s already linked that %d %s ago.\n",
       +                 user, whostart, unit_number, unit);
       +          break;
       +        case 1:
       +          printf("%s: Comrade!  That link was first seen %d %s ago!\n",
       +                 user, unit_number, unit);
       +          break;
       +        case 2:
       +          printf("%s: How nostalgic!  Just like %s a whole %d %s ago!\n",
       +                 user, whostart, unit_number, unit);
       +          break;
       +        }
       +      }
       +    }
       +  }
       +  /* Always log */
       +  fprintf(linksf, "%s %ld %s\n", link, (long int)now, user);
       +}
       +
       +int main(int argc, char** argv) {
       +  assert(argc == 4);
       +  char* dbfile = argv[1];
       +  char* user = argv[2];
       +  char* message = argv[3];
       +
       +  now = time(NULL);
       +  srand(now);
       +
       +  if (message != NULL && user != NULL) {
       +    struct stat fs;
       +
       +    userlength = strlen(user);
       +    linksf = fopen(dbfile, "a+");
       +    assert(linksf != NULL);
       +    fstat(fileno(linksf), &fs);
       +    linkslength = fs.st_size;
       +    links = mmap(NULL, linkslength, PROT_WRITE | PROT_READ, MAP_PRIVATE, fileno(linksf), 0);
       +    while (1) {
       +      char* start, *end;
       +      int atend;
       +
       +      start = strstr(message, "http://");
       +
       +      if (start == NULL) {
       +        start = strstr(message, "https://");
       +      }
       +
       +      if (start == NULL) {
       +        start = strstr(message, "gopher://");
       +      }
       +
       +      if (start == NULL) {
       +        start = strstr(message, "gophers://");
       +      }
       +
       +      if (start == NULL) {
       +        return 0;
       +      }
       +
       +      end = start;
       +
       +      while (*end != ' ' && *end != 0) {
       +        end++;
       +      }
       +
       +      atend = *end == 0;
       +      *end = 0;
       +
       +      checklink(user, start);
       +
       +      if (atend) {
       +        return 0;
       +      }
       +
       +      message = end+1;
       +    }
       +    return 0;
       +  } else {
       +    return 1;
       +  }
       +}
   DIR diff --git a/modules/linkbrother/linkbrother.sh b/modules/linkbrother/linkbrother.sh
       @@ -0,0 +1,12 @@
       +#!/bin/sh
       +#
       +# State-of-the-art JIT compilation of linkbrother.
       +
       +set -e
       +
       +dir=$(dirname $0)
       +if ! [ -x "$dir/linkbrother" -a "$dir/linkbrother" -nt "$dir/linkbrother.c" ]; then
       +    cc "$dir/linkbrother.c" -o "$dir/linkbrother"
       +fi
       +
       +"$dir/linkbrother" "$@"