sfeed

Simple RSS and Atom feed parser
git clone https://git.sinitax.com/codemadness/sfeed
Log | Files | Refs | README | LICENSE | Upstream | sfeed.txt

sfeed_gopher.c (4404B)


      1#include <stdio.h>
      2#include <stdlib.h>
      3#include <string.h>
      4#include <time.h>
      5
      6#include "util.h"
      7
      8static char *prefixpath = "/", *host = "127.0.0.1", *port = "70"; /* default */
      9static char *line;
     10static size_t linesize;
     11static time_t comparetime;
     12
     13/* Escape characters in gopher, CR and LF are ignored */
     14static void
     15gophertext(FILE *fp, const char *s)
     16{
     17	for (; *s; s++) {
     18		switch (*s) {
     19		case '\r': /* ignore CR */
     20		case '\n': /* ignore LF */
     21			break;
     22		case '\t':
     23			fputs("        ", fp);
     24			break;
     25		default:
     26			putc(*s, fp);
     27			break;
     28		}
     29	}
     30}
     31
     32static void
     33printfeed(FILE *fpitems, FILE *fpin, struct feed *f)
     34{
     35	struct uri u;
     36	char *fields[FieldLast];
     37	char *itemhost, *itemport, *itempath, *itemquery, *itemfragment;
     38	ssize_t linelen;
     39	unsigned int isnew;
     40	struct tm rtm, *tm;
     41	time_t parsedtime;
     42	int itemtype;
     43
     44	if (f->name[0]) {
     45		fprintf(fpitems, "i%s\t\t%s\t%s\r\n", f->name, host, port);
     46		fprintf(fpitems, "i\t\t%s\t%s\r\n", host, port);
     47	}
     48
     49	while ((linelen = getline(&line, &linesize, fpin)) > 0 &&
     50	       !ferror(fpitems)) {
     51		if (line[linelen - 1] == '\n')
     52			line[--linelen] = '\0';
     53		parseline(line, fields);
     54
     55		itemhost = host;
     56		itemport = port;
     57		itemtype = 'i';
     58		itempath = fields[FieldLink];
     59		itemquery = "";
     60		itemfragment = "";
     61
     62		if (fields[FieldLink][0]) {
     63			itemtype = 'h';
     64			/* if it is a gopher URL then change it into a DirEntity */
     65			if (!strncmp(fields[FieldLink], "gopher://", 9) &&
     66			    uri_parse(fields[FieldLink], &u) != -1) {
     67				itemhost = u.host;
     68				itemport = u.port[0] ? u.port : "70";
     69				itemtype = '1';
     70				itempath = u.path;
     71				itemquery = u.query;
     72				itemfragment = u.fragment;
     73
     74				if (itempath[0] == '/') {
     75					itempath++;
     76					if (*itempath) {
     77						itemtype = *itempath;
     78						itempath++;
     79					}
     80				}
     81			}
     82		}
     83
     84		parsedtime = 0;
     85		if (!strtotime(fields[FieldUnixTimestamp], &parsedtime) &&
     86		    (tm = localtime_r(&parsedtime, &rtm))) {
     87			isnew = (parsedtime >= comparetime) ? 1 : 0;
     88			f->totalnew += isnew;
     89
     90			fprintf(fpitems, "%c%c %04d-%02d-%02d %02d:%02d ",
     91			        itemtype,
     92			        isnew ? 'N' : ' ',
     93			        tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
     94			        tm->tm_hour, tm->tm_min);
     95		} else {
     96			fprintf(fpitems, "%c                   ", itemtype);
     97		}
     98		f->total++;
     99
    100		gophertext(fpitems, fields[FieldTitle]);
    101		fputs("\t", fpitems);
    102		if (itemtype == 'h' && fields[FieldLink] == itempath)
    103			fputs("URL:", fpitems);
    104		gophertext(fpitems, itempath);
    105		if (itemquery[0]) {
    106			fputs("?", fpitems);
    107			gophertext(fpitems, itemquery);
    108		}
    109		if (itemfragment[0]) {
    110			fputs("#", fpitems);
    111			gophertext(fpitems, itemfragment);
    112		}
    113		fprintf(fpitems, "\t%s\t%s\r\n", itemhost, itemport);
    114	}
    115	fputs(".\r\n", fpitems);
    116}
    117
    118int
    119main(int argc, char *argv[])
    120{
    121	struct feed f = { 0 };
    122	FILE *fpitems, *fpindex, *fp;
    123	char *name, *p;
    124	int i;
    125
    126	if (argc == 1) {
    127		if (pledge("stdio", NULL) == -1)
    128			err(1, "pledge");
    129	} else {
    130		if (unveil("/", "r") == -1)
    131			err(1, "unveil: /");
    132		if (unveil(".", "rwc") == -1)
    133			err(1, "unveil: .");
    134		if (pledge("stdio rpath wpath cpath", NULL) == -1)
    135			err(1, "pledge");
    136	}
    137
    138	if ((comparetime = getcomparetime()) == (time_t)-1)
    139		errx(1, "getcomparetime");
    140
    141	if ((p = getenv("SFEED_GOPHER_HOST")))
    142		host = p;
    143	if ((p = getenv("SFEED_GOPHER_PORT")))
    144		port = p;
    145
    146	if (argc == 1) {
    147		f.name = "";
    148		printfeed(stdout, stdin, &f);
    149		checkfileerror(stdin, "<stdin>", 'r');
    150		checkfileerror(stdout, "<stdout>", 'w');
    151	} else {
    152		if ((p = getenv("SFEED_GOPHER_PATH")))
    153			prefixpath = p;
    154
    155		/* write main index page */
    156		if (!(fpindex = fopen("index", "wb")))
    157			err(1, "fopen: index");
    158
    159		for (i = 1; i < argc; i++) {
    160			memset(&f, 0, sizeof(f));
    161			name = ((name = strrchr(argv[i], '/'))) ? name + 1 : argv[i];
    162			f.name = name;
    163
    164			if (!(fp = fopen(argv[i], "r")))
    165				err(1, "fopen: %s", argv[i]);
    166			if (!(fpitems = fopen(name, "wb")))
    167				err(1, "fopen");
    168			printfeed(fpitems, fp, &f);
    169			checkfileerror(fp, argv[i], 'r');
    170			checkfileerror(fpitems, name, 'w');
    171			fclose(fp);
    172			fclose(fpitems);
    173
    174			/* append directory item to index */
    175			fputs("1", fpindex);
    176			gophertext(fpindex, name);
    177			fprintf(fpindex, " (%lu/%lu)\t", f.totalnew, f.total);
    178			gophertext(fpindex, prefixpath);
    179			gophertext(fpindex, name);
    180			fprintf(fpindex, "\t%s\t%s\r\n", host, port);
    181		}
    182		fputs(".\r\n", fpindex);
    183		checkfileerror(fpindex, "index", 'w');
    184		fclose(fpindex);
    185	}
    186
    187	return 0;
    188}