URI:
       sfeed_frames_content: add old archived sfeed_frames version with content - randomcrap - random crap programs of varying quality
  HTML git clone git://git.codemadness.org/randomcrap
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit b952e0706644f6ae41c607afabab59e4a44f7580
   DIR parent 941ecd1ec38a5d0b4e7b4f3ed3e9ea6234b6ed8b
  HTML Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Sat, 18 Mar 2023 19:56:56 +0100
       
       sfeed_frames_content: add old archived sfeed_frames version with content
       
       This was a version of sfeed_frames which saved the HTML content per file.
       
       Backport some recent changes of the format tools (localtime_r, unveil,
       parseline, etc).
       
       From sfeed commit b7e288a96418e1ea5e7904ab2896edb3f4615a10:
       
               Date:   Thu Aug 16 14:16:58 2018 +0200
               sfeed_frames: overhaul
       
       Diffstat:
         A sfeed/sfeed_frames_content.c        |     345 +++++++++++++++++++++++++++++++
       
       1 file changed, 345 insertions(+), 0 deletions(-)
       ---
   DIR diff --git a/sfeed/sfeed_frames_content.c b/sfeed/sfeed_frames_content.c
       @@ -0,0 +1,345 @@
       +#include <sys/stat.h>
       +#include <sys/types.h>
       +
       +#include <err.h>
       +#include <errno.h>
       +#include <fcntl.h>
       +#include <limits.h>
       +#include <stdarg.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <time.h>
       +#include <unistd.h>
       +#include <utime.h>
       +
       +#include "util.h"
       +
       +static struct feed **feeds;
       +static char *line;
       +static size_t linesize;
       +static struct timespec times[2];
       +static time_t comparetime;
       +static unsigned long totalnew, total;
       +
       +/* Unescape / decode fields printed by string_print_encoded()
       + * "\\" to "\", "\t", to TAB, "\n" to newline. Unrecognised escape sequences
       + * are ignored: "\z" etc. */
       +static void
       +printcontent(const char *s, FILE *fp)
       +{
       +        for (; *s; s++) {
       +                switch (*s) {
       +                case '\\':
       +                        switch (*(++s)) {
       +                        case '\0': return; /* ignore */
       +                        case '\\': putc('\\', fp); break;
       +                        case 't':  putc('\t', fp); break;
       +                        case 'n':  putc('\n', fp); break;
       +                        }
       +                        break;
       +                default:
       +                        putc(*s, fp);
       +                }
       +        }
       +}
       +
       +/* Unescape / decode fields printed by string_print_encoded()
       + * "\\" to "\", "\t", to TAB, "\n" to newline. Unrecognised escape sequences
       + * are ignored: "\z" etc. Encode HTML 2.0 / XML 1.0 entities.  */
       +static void
       +printcontentxml(const char *s, FILE *fp)
       +{
       +        for (; *s; s++) {
       +                switch (*s) {
       +                case '\\':
       +                        switch (*(++s)) {
       +                        case '\0': return; /* ignore */
       +                        case '\\': putc('\\', fp); break;
       +                        case 't':  putc('\t', fp); break;
       +                        case 'n':  putc('\n', fp); break;
       +                        }
       +                        break;
       +                /* XML entities */
       +                case '<':  fputs("&lt;",   fp); break;
       +                case '>':  fputs("&gt;",   fp); break;
       +                case '\'': fputs("&#39;",  fp); break;
       +                case '&':  fputs("&amp;",  fp); break;
       +                case '"':  fputs("&quot;", fp); break;
       +                default:   putc(*s, fp);
       +                }
       +        }
       +}
       +
       +/* normalize path names, transform to lower-case and replace non-alpha and
       + * non-digit with '-' */
       +static size_t
       +normalizepath(const char *path, char *buf, size_t bufsiz)
       +{
       +        size_t i, r = 0;
       +
       +        for (i = 0; *path && i < bufsiz - 1; path++) {
       +                if (ISALPHA((unsigned char)*path) || ISDIGIT((unsigned char)*path)) {
       +                        buf[i++] = TOLOWER((unsigned char)*path);
       +                        r = 0;
       +                } else {
       +                        /* don't repeat '-', don't start with '-' */
       +                        if (!r && i)
       +                                buf[i++] = '-';
       +                        r++;
       +                }
       +        }
       +        /* remove trailing '-' */
       +        for (; i > 0 && (buf[i - 1] == '-'); i--)
       +                ;
       +
       +        buf[i] = '\0';
       +
       +        return i;
       +}
       +
       +static void
       +printfeed(FILE *fpitems, FILE *fpin, struct feed *f)
       +{
       +        char dirpath[PATH_MAX], filepath[PATH_MAX];
       +        char *fields[FieldLast], *feedname, name[128];
       +        ssize_t linelen;
       +        FILE *fpcontent = NULL;
       +        unsigned int isnew;
       +        struct tm rtm, *tm;
       +        time_t parsedtime;
       +        int fd, r;
       +
       +        if (f->name[0])
       +                feedname = f->name;
       +        else
       +                feedname = "unnamed";
       +
       +        /* make directory for feedname */
       +        if (!normalizepath(feedname, name, sizeof(name)))
       +                return;
       +
       +        strlcpy(dirpath, name, sizeof(dirpath));
       +
       +        /* error creating directory and it doesn't exist. */
       +        if (mkdir(dirpath, S_IRWXU | S_IRWXG | S_IRWXO) == -1 && errno != EEXIST)
       +                err(1, "mkdir: %s", dirpath);
       +
       +        /* menu if not unnamed */
       +        if (f->name[0]) {
       +                fputs("<h2 id=\"", fpitems);
       +                xmlencode(f->name, fpitems);
       +                fputs("\"><a href=\"#", fpitems);
       +                xmlencode(f->name, fpitems);
       +                fputs("\">", fpitems);
       +                xmlencode(f->name, fpitems);
       +                fputs("</a></h2>\n", fpitems);
       +        }
       +
       +        while ((linelen = getline(&line, &linesize, fpin)) > 0) {
       +                if (line[linelen - 1] == '\n')
       +                        line[--linelen] = '\0';
       +                parseline(line, fields);
       +
       +                parsedtime = 0;
       +                if (strtotime(fields[FieldUnixTimestamp], &parsedtime))
       +                        continue;
       +                if (!(tm = localtime_r(&parsedtime, &rtm)))
       +                        err(1, "localtime");
       +
       +                if (!normalizepath(fields[FieldTitle], name, sizeof(name)))
       +                        continue;
       +
       +                r = snprintf(filepath, sizeof(filepath), "%s/%s-%lld.html",
       +                             dirpath, name, (long long)parsedtime);
       +                if (r == -1 || (size_t)r >= sizeof(filepath))
       +                        errx(1, "snprintf: path truncation: '%s/%s-%lld.html'",
       +                                dirpath, name, (long long)parsedtime);
       +
       +                /* content file doesn't exist yet and has error? */
       +                if ((fd = open(filepath, O_CREAT | O_EXCL | O_WRONLY,
       +                               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1) {
       +                        if (errno != EEXIST)
       +                                err(1, "open: %s", filepath);
       +                } else {
       +                        if (!(fpcontent = fdopen(fd, "wb")))
       +                                err(1, "fdopen: %s", filepath);
       +                        fputs("<html><head>"
       +                              "<link rel=\"stylesheet\" type=\"text/css\" href=\"../../style.css\" />"
       +                              "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />"
       +                              "</head>\n<body class=\"frame\">"
       +                              "<div class=\"content\"><h2>", fpcontent);
       +
       +                        if (fields[FieldLink][0]) {
       +                                fputs("<a href=\"", fpcontent);
       +                                xmlencode(fields[FieldLink], fpcontent);
       +                                fputs("\">", fpcontent);
       +                        }
       +                        xmlencode(fields[FieldTitle], fpcontent);
       +                        if (fields[FieldLink][0])
       +                                fputs("</a>", fpcontent);
       +                        fputs("</h2>", fpcontent);
       +
       +                        /* NOTE: this prints the raw HTML of the feed, this is
       +                         * potentially dangerous, it is left up to the
       +                         * user / browser to trust a feed it's HTML content. */
       +                        if (!strcmp(fields[FieldContentType], "html")) {
       +                                printcontent(fields[FieldContent], fpcontent);
       +                        } else {
       +                                /* plain-text, wrap with <pre> */
       +                                fputs("<pre>", fpcontent);
       +                                printcontentxml(fields[FieldContent], fpcontent);
       +                                fputs("</pre>", fpcontent);
       +                        }
       +                        fputs("</div></body></html>\n", fpcontent);
       +
       +                        /* set modified and access time of file to time of item. */
       +                        if (parsedtime) {
       +                                /* flush writes before setting atime and mtime
       +                                   else the remaining (buffered) write can occur at
       +                                   fclose() and overwrite our time again. */
       +                                fflush(fpcontent);
       +
       +                                times[0].tv_sec = parsedtime;
       +                                times[1].tv_sec = parsedtime;
       +
       +                                if (futimens(fd, times) == -1)
       +                                        err(1, "futimens");
       +                        }
       +                        fclose(fpcontent);
       +                }
       +
       +                isnew = (parsedtime >= comparetime) ? 1 : 0;
       +                totalnew += isnew;
       +                f->totalnew += isnew;
       +                f->total++;
       +                total++;
       +
       +                fprintf(fpitems, "%04d-%02d-%02d&nbsp;%02d:%02d ",
       +                        tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
       +                        tm->tm_hour, tm->tm_min);
       +
       +                if (isnew)
       +                        fputs("<b><u>", fpitems);
       +                fputs("<a href=\"", fpitems);
       +                fputs(filepath, fpitems);
       +                fputs("\" target=\"content\">", fpitems);
       +                xmlencode(fields[FieldTitle], fpitems);
       +                fputs("</a>", fpitems);
       +                if (isnew)
       +                        fputs("</u></b>", fpitems);
       +                fputs("\n", fpitems);
       +        }
       +}
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        FILE *fpindex, *fpitems, *fpmenu = NULL, *fp;
       +        char *name;
       +        int i, showsidebar = (argc > 1);
       +        struct feed *f;
       +
       +        if (unveil("/", "r") == -1)
       +                err(1, "unveil: /");
       +        if (unveil(".", "rwc") == -1)
       +                err(1, "unveil: .");
       +        if (pledge("stdio rpath wpath cpath fattr", NULL) == -1)
       +                err(1, "pledge");
       +
       +        if (!(feeds = calloc(argc, sizeof(struct feed *))))
       +                err(1, "calloc");
       +
       +        if ((comparetime = time(NULL)) == -1)
       +                errx(1, "time");
       +        /* 1 day is old news */
       +        comparetime -= 86400;
       +
       +        /* write main index page */
       +        if (!(fpindex = fopen("index.html", "wb")))
       +                err(1, "fopen: index.html");
       +        if (!(fpitems = fopen("items.html", "wb")))
       +                err(1, "fopen: items.html");
       +        if (showsidebar && !(fpmenu = fopen("menu.html", "wb")))
       +                err(1, "fopen: menu.html");
       +        fputs("<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"../style.css\" />"
       +              "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /></head>"
       +              "<body class=\"frame\"><div id=\"items\"><pre>", fpitems);
       +
       +        if (argc == 1) {
       +                if (!(feeds[0] = calloc(1, sizeof(struct feed))))
       +                        err(1, "calloc");
       +                feeds[0]->name = "";
       +                printfeed(fpitems, stdin, feeds[0]);
       +                checkfileerror(stdin, "<stdin>", 'r');
       +        } else {
       +                for (i = 1; i < argc; i++) {
       +                        if (!(feeds[i - 1] = calloc(1, sizeof(struct feed))))
       +                                err(1, "calloc");
       +                        name = ((name = strrchr(argv[i], '/'))) ? name + 1 : argv[i];
       +                        feeds[i - 1]->name = name;
       +
       +                        if (!(fp = fopen(argv[i], "r")))
       +                                err(1, "fopen: %s", argv[i]);
       +                        printfeed(fpitems, fp, feeds[i - 1]);
       +                        checkfileerror(fp, argv[i], 'r');
       +                        checkfileerror(fpitems, "items.html", 'w');
       +                        fclose(fp);
       +                }
       +        }
       +        fputs("</pre>\n</div></body>\n</html>\n", fpitems); /* div items */
       +
       +        if (showsidebar) {
       +                fputs("<html><head>"
       +                      "<link rel=\"stylesheet\" type=\"text/css\" href=\"../style.css\" />\n"
       +                      "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n"
       +                      "</head><body class=\"frame\"><div id=\"sidebar\">", fpmenu);
       +
       +                for (i = 1; i < argc; i++) {
       +                        f = feeds[i - 1];
       +                        if (f->totalnew)
       +                                fputs("<a class=\"n\" href=\"items.html#", fpmenu);
       +                        else
       +                                fputs("<a href=\"items.html#", fpmenu);
       +                        xmlencode(f->name, fpmenu);
       +                        fputs("\" target=\"items\">", fpmenu);
       +                        if (f->totalnew > 0)
       +                                fputs("<b><u>", fpmenu);
       +                        xmlencode(f->name, fpmenu);
       +                        fprintf(fpmenu, " (%lu)", f->totalnew);
       +                        if (f->totalnew > 0)
       +                                fputs("</u></b>", fpmenu);
       +                        fputs("</a><br/>\n", fpmenu);
       +                }
       +                fputs("</div></body></html>\n", fpmenu);
       +        }
       +        fputs("<!DOCTYPE html><html><head>\n\t<title>(", fpindex);
       +        fprintf(fpindex, "%lu/%lu", totalnew, total);
       +        fputs(") - Newsfeed</title>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"../style.css\" />\n"
       +              "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n"
       +              "</head>\n", fpindex);
       +        if (showsidebar) {
       +                fputs("<frameset framespacing=\"0\" cols=\"200,*\" frameborder=\"1\">\n"
       +                      "        <frame name=\"menu\" src=\"menu.html\" target=\"menu\">\n", fpindex);
       +        } else {
       +                fputs("<frameset framespacing=\"0\" cols=\"*\" frameborder=\"1\">\n", fpindex);
       +        }
       +        fputs("\t<frameset id=\"frameset\" framespacing=\"0\" cols=\"50%,50%\" frameborder=\"1\">\n"
       +              "\t\t<frame name=\"items\" src=\"items.html\" target=\"items\">\n"
       +              "\t\t<frame name=\"content\" target=\"content\">\n"
       +              "\t</frameset>\n"
       +              "</frameset>\n"
       +              "</html>\n", fpindex);
       +
       +        checkfileerror(fpindex, "index.html", 'w');
       +        checkfileerror(fpitems, "items.html", 'w');
       +
       +        fclose(fpitems);
       +        fclose(fpindex);
       +        if (fpmenu) {
       +                checkfileerror(fpmenu, "menu.html", 'w');
       +                fclose(fpmenu);
       +        }
       +
       +        return 0;
       +}