A simple RSS feed downloader that saves items in a Maildir
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

144 lines
3.1 KiB

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "parse.h"
#include "save.h"
#include "xml.h"
#ifndef OpenBSD
#include "strlcpy.h"
#endif
#define istag(name) strcmp(x->tag, name) == 0
int isatom = 0;
int isitem = 0;
char feedtitle[256];
struct rss_item item;
static void xmlattr(XMLParser *, const char *, size_t, const char *, size_t,
const char *, size_t);
static void xmldata(XMLParser *, const char *, size_t);
static void xmldataentity(XMLParser *, const char *, size_t);
static void xmltagend(XMLParser *, const char *, size_t, int);
static void xmltagstart(XMLParser *, const char *, size_t);
static void rfc822_date(char *);
void
xmlattr(XMLParser *x, const char *t, size_t tl, const char *a, size_t al,
const char *v, size_t vl)
{
if (!isatom || !(istag("link")))
return;
if (strcmp(x->name, "href") == 0)
strlcpy(item.link, x->data, sizeof(item.link));
}
static void
xmldata(XMLParser *x, const char *d, size_t dl)
{
if (isitem == 0) {
if (istag("title"))
strlcpy(feedtitle, d, sizeof(feedtitle));
return;
}
if (istag("title"))
strlcpy(item.title, d, sizeof(item.title));
else if (!isatom && istag("link"))
strlcpy(item.link, d, sizeof(item.link));
else if (istag("pubDate") || istag("updated") || istag("dc:date"))
strlcpy(item.date, d, sizeof(item.date));
else if (istag("summary") || istag("content") || istag("description"))
fputs(d, item.desc);
}
static void
xmldataentity(XMLParser *x, const char *d, size_t dl)
{
char buf[16];
int len;
/*
* try to translate entity, else just pass as data to xmldata
* handler.
*/
if ((len = xml_entitytostr(d, buf, sizeof(buf))) > 0)
xmldata(x, buf, (size_t) len);
else
xmldata(x, d, dl);
}
static void
xmltagend(XMLParser *x, const char *t, size_t tl, int isshort)
{
if (isitem == 0)
return;
if (istag("item") || istag("entry")) {
isitem = 0;
fseek(item.desc, 0, SEEK_SET);
rfc822_date(item.date);
save_item(item, feedtitle);
fclose(item.desc);
item.desc = NULL;
memset(&item, 0, sizeof(struct rss_item));
}
}
static void
xmltagstart(XMLParser *x, const char *t, size_t tl)
{
if (istag("feed")) {
isatom = 1;
return;
}
if (istag("item") || istag("entry")) {
isitem = 1;
snprintf(item.descfn, sizeof(item.descfn), "tmp/desc.%6x", rand());
item.desc = fopen(item.descfn, "w+");
}
}
static void
rfc822_date(char *date)
{
struct tm time;
memset(&time, 0, sizeof(struct tm));
if (strptime(date, "%a, %d %b %Y %T %z", &time) ||
strptime(date, "%a, %d %b %Y %T %Z", &time) ||
strptime(date, "%a, %d %b %Y %T", &time) ||
strptime(date, "%Y-%m-%dT%TZ", &time) ||
strptime(date, "%Y-%m-%d", &time)) {
item.epochsec = mktime(&time);
strftime(date, sizeof(item.date), "%a, %d %b %Y %T %z", &time);
} else
fprintf(stderr, "strptime failed when converting pubdate to epoch\n");
}
int
parse_item(void)
{
XMLParser x = {0};
x.xmlattr = xmlattr;
x.xmldata = xmldata;
x.xmldataentity = xmldataentity;
x.xmlcdata = xmldata;
x.xmltagend = xmltagend;
x.xmltagstart = xmltagstart;
x.getnext = getchar;
xml_parse(&x);
return 0;
}