198 lines
4.5 KiB
C
198 lines
4.5 KiB
C
#include <sys/types.h>
|
|
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.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:
|
|
putc(*s, fp);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
printfeed(FILE *fpitems, FILE *fpin, struct feed *f)
|
|
{
|
|
struct uri u;
|
|
char *fields[FieldLast];
|
|
char *itemhost, *itemport, *itempath, *itemquery, *itemfragment;
|
|
ssize_t linelen;
|
|
unsigned int isnew;
|
|
struct tm rtm, *tm;
|
|
time_t parsedtime;
|
|
int itemtype;
|
|
|
|
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 &&
|
|
!ferror(fpitems)) {
|
|
if (line[linelen - 1] == '\n')
|
|
line[--linelen] = '\0';
|
|
parseline(line, fields);
|
|
|
|
itemhost = host;
|
|
itemport = port;
|
|
itemtype = 'i';
|
|
itempath = fields[FieldLink];
|
|
itemquery = "";
|
|
itemfragment = "";
|
|
|
|
if (fields[FieldLink][0]) {
|
|
itemtype = 'h';
|
|
/* if it's a gopher URL then change it into a DirEntity */
|
|
if (!strncmp(fields[FieldLink], "gopher://", 9) &&
|
|
uri_parse(fields[FieldLink], &u) != -1) {
|
|
itemhost = u.host;
|
|
itemport = u.port[0] ? u.port : "70";
|
|
itemtype = '1';
|
|
itempath = u.path;
|
|
itemquery = u.query;
|
|
itemfragment = u.fragment;
|
|
|
|
if (itempath[0] == '/') {
|
|
itempath++;
|
|
if (*itempath) {
|
|
itemtype = *itempath;
|
|
itempath++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
parsedtime = 0;
|
|
if (!strtotime(fields[FieldUnixTimestamp], &parsedtime) &&
|
|
(tm = localtime_r(&parsedtime, &rtm))) {
|
|
isnew = (parsedtime >= comparetime) ? 1 : 0;
|
|
f->totalnew += isnew;
|
|
|
|
fprintf(fpitems, "%c%c %04d-%02d-%02d %02d:%02d ",
|
|
itemtype,
|
|
isnew ? 'N' : ' ',
|
|
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
|
tm->tm_hour, tm->tm_min);
|
|
} else {
|
|
fprintf(fpitems, "%c ", itemtype);
|
|
}
|
|
f->total++;
|
|
|
|
gophertext(fpitems, fields[FieldTitle]);
|
|
fputs("\t", fpitems);
|
|
if (itemtype == 'h' && fields[FieldLink] == itempath)
|
|
fputs("URL:", fpitems);
|
|
gophertext(fpitems, itempath);
|
|
if (itemquery[0]) {
|
|
fputs("?", fpitems);
|
|
gophertext(fpitems, itemquery);
|
|
}
|
|
if (itemfragment[0]) {
|
|
fputs("#", fpitems);
|
|
gophertext(fpitems, itemfragment);
|
|
}
|
|
fprintf(fpitems, "\t%s\t%s\r\n", itemhost, itemport);
|
|
}
|
|
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 (argc == 1) {
|
|
if (pledge("stdio", NULL) == -1)
|
|
err(1, "pledge");
|
|
} else {
|
|
if (unveil("/", "r") == -1)
|
|
err(1, "unveil: /");
|
|
if (unveil(".", "rwc") == -1)
|
|
err(1, "unveil: .");
|
|
if (pledge("stdio rpath wpath cpath", NULL) == -1)
|
|
err(1, "pledge");
|
|
}
|
|
|
|
if ((comparetime = time(NULL)) == (time_t)-1)
|
|
errx(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);
|
|
checkfileerror(stdin, "<stdin>", 'r');
|
|
checkfileerror(stdout, "<stdout>", 'w');
|
|
} 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);
|
|
checkfileerror(fp, argv[i], 'r');
|
|
checkfileerror(fpitems, path, 'w');
|
|
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);
|
|
checkfileerror(fpindex, "index", 'w');
|
|
fclose(fpindex);
|
|
}
|
|
|
|
return 0;
|
|
}
|