summaryrefslogtreecommitdiff
path: root/sfeed_gopher.c
diff options
context:
space:
mode:
authorHiltjo Posthuma <hiltjo@codemadness.org>2020-01-18 19:19:41 +0100
committerHiltjo Posthuma <hiltjo@codemadness.org>2020-01-18 20:09:42 +0100
commit009f6e1affd8c8501f66526f100bfa273307e640 (patch)
tree9e1d5ad41be849f24a09f8080bb27dcfda46c552 /sfeed_gopher.c
parent018278e40b6794b23f98f57f154bfa1a30d56672 (diff)
add sfeed_gopher: generic gopher formatting program, remove sfeed_gph
Diffstat (limited to 'sfeed_gopher.c')
-rw-r--r--sfeed_gopher.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/sfeed_gopher.c b/sfeed_gopher.c
new file mode 100644
index 0000000..4100c62
--- /dev/null
+++ b/sfeed_gopher.c
@@ -0,0 +1,159 @@
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ctype.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 "util.h"
+
+static struct feed f;
+static char *prefixpath = "/", *host = "127.0.0.1", *port = "70"; /* default */
+static char *line;
+static size_t linesize;
+static time_t comparetime;
+
+/* Escape characters in gopher, CR and LF are ignored */
+void
+gophertext(FILE *fp, const char *s)
+{
+ for (; *s; s++) {
+ switch (*s) {
+ case '\r': /* ignore CR */
+ case '\n': /* ignore LF */
+ break;
+ case '\t':
+ fputs(" ", fp);
+ break;
+ default:
+ fputc(*s, fp);
+ break;
+ }
+ }
+}
+
+static void
+printfeed(FILE *fpitems, FILE *fpin, struct feed *f)
+{
+ char *fields[FieldLast];
+ ssize_t linelen;
+ unsigned int isnew;
+ struct tm *tm;
+ time_t parsedtime;
+
+ if (f->name[0]) {
+ fprintf(fpitems, "i%s\t\t%s\t%s\r\n", f->name, host, port);
+ fprintf(fpitems, "i\t\t%s\t%s\r\n", host, port);
+ }
+
+ while ((linelen = getline(&line, &linesize, fpin)) > 0) {
+ if (line[linelen - 1] == '\n')
+ line[--linelen] = '\0';
+ if (!parseline(line, fields))
+ break;
+
+ parsedtime = 0;
+ if (strtotime(fields[FieldUnixTimestamp], &parsedtime))
+ continue;
+ if (!(tm = localtime(&parsedtime)))
+ err(1, "localtime");
+
+ isnew = (parsedtime >= comparetime) ? 1 : 0;
+ f->totalnew += isnew;
+ f->total++;
+
+ if (fields[FieldLink][0]) {
+ fputs("h", fpitems);
+ fprintf(fpitems, "%c %04d-%02d-%02d %02d:%02d ",
+ isnew ? 'N' : ' ',
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min);
+ gophertext(fpitems, fields[FieldTitle]);
+ fputs("\tURL:", fpitems);
+ gophertext(fpitems, fields[FieldLink]);
+
+ } else {
+ fprintf(fpitems, "i%c %04d-%02d-%02d %02d:%02d ",
+ isnew ? 'N' : ' ',
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min);
+ gophertext(fpitems, fields[FieldTitle]);
+ fputs("\t", fpitems);
+ }
+ fprintf(fpitems, "\t%s\t%s\r\n", host, port);
+ }
+ fputs(".\r\n", fpitems);
+}
+
+int
+main(int argc, char *argv[])
+{
+ FILE *fpitems, *fpindex, *fp;
+ char *name, *p, path[PATH_MAX + 1];
+ int i, r;
+
+ if (pledge(argc == 1 ? "stdio" : "stdio rpath wpath cpath", NULL) == -1)
+ err(1, "pledge");
+
+ if ((comparetime = time(NULL)) == -1)
+ err(1, "time");
+ /* 1 day is old news */
+ comparetime -= 86400;
+
+ if ((p = getenv("SFEED_GOPHER_HOST")))
+ host = p;
+ if ((p = getenv("SFEED_GOPHER_PORT")))
+ port = p;
+
+ if (argc == 1) {
+ f.name = "";
+ printfeed(stdout, stdin, &f);
+ } else {
+ if ((p = getenv("SFEED_GOPHER_PATH")))
+ prefixpath = p;
+
+ /* write main index page */
+ if (!(fpindex = fopen("index", "wb")))
+ err(1, "fopen: index");
+
+ for (i = 1; i < argc; i++) {
+ memset(&f, 0, sizeof(f));
+ name = ((name = strrchr(argv[i], '/'))) ? name + 1 : argv[i];
+ f.name = name;
+
+ if (!(fp = fopen(argv[i], "r")))
+ err(1, "fopen: %s", argv[i]);
+
+ r = snprintf(path, sizeof(path), "%s", name);
+ if (r < 0 || (size_t)r >= sizeof(path))
+ errx(1, "path truncation: %s", path);
+ if (!(fpitems = fopen(path, "wb")))
+ err(1, "fopen");
+ printfeed(fpitems, fp, &f);
+ if (ferror(fp))
+ err(1, "ferror: %s", argv[i]);
+ fclose(fp);
+ fclose(fpitems);
+
+ /* append directory item to index */
+ fputs("1", fpindex);
+ gophertext(fpindex, name);
+ fprintf(fpindex, " (%lu/%lu)\t", f.totalnew, f.total);
+ gophertext(fpindex, prefixpath);
+ gophertext(fpindex, path);
+ fprintf(fpindex, "\t%s\t%s\r\n", host, port);
+ }
+ fputs(".\r\n", fpindex);
+ fclose(fpindex);
+ }
+
+ return 0;
+}