commit d42fe37ed17a238e006cff6967105da64dd36b13
parent c45e2fd11bf7b654631b1135baf8c4e8abf48a66
Author: Paco Esteban <paco@e1e0.net>
Date: Wed, 1 Jul 2020 16:37:10 +0200
add rss generation
Diffstat:
M | helpers.h | | | 1 | + |
M | ssnail.c | | | 132 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
2 files changed, 128 insertions(+), 5 deletions(-)
diff --git a/helpers.h b/helpers.h
@@ -20,6 +20,7 @@
#define HEADER "_header.html"
#define FOOTER "_footer.html"
#define SHORT_DATE_Z 12
+#define LONG_DATE_Z 32
const struct ssnail_error *copy_file(const char *, const char *, int);
diff --git a/ssnail.c b/ssnail.c
@@ -58,6 +58,7 @@ __dead static void usage(void);
static void free_article(struct article *);
static void free_articleq(struct listhead *);
static void add_index_entry(char **, struct article *);
+static void add_rss_entry(char **, struct article *, char *);
struct article *init_article(void);
static struct article *populate_article_entry(char *, char *);
@@ -67,12 +68,13 @@ static const struct ssnail_error *process_dir(char *, char *, int);
static const struct ssnail_error *write_html(struct article *, char *, char *);
static const struct ssnail_error *sort_articleq(struct listhead *);
static const struct ssnail_error *gen_html(struct article *);
+static const struct ssnail_error *write_rss(char *, char *, char *, char *);
__dead static void
usage(void)
{
- fprintf(stderr, "usage: %s [-F] [-f footer] [-h header] [-i] "
- "src_folder dst_folder\n", getprogname());
+ fprintf(stderr, "usage: %s [-F] [-f footer] [-h header] [-i] [-r] "
+ "-t <title> -u <url> src_folder dst_folder\n", getprogname());
exit(1);
}
@@ -82,9 +84,10 @@ main(int argc, char *argv[])
struct article *ap = NULL, *ip = NULL;
const struct ssnail_error *error = NULL;
- int ch, index = 0, force = 0;
+ int ch, index = 0, rss = 0, force = 0;
char *header_tpl = NULL, *footer_tpl = NULL,
- *index_listing = "";
+ *index_listing = "", *rss_listing = "",
+ *title = NULL, *url = NULL;
header_tpl = strdup(HEADER);
if (header_tpl == NULL) {
@@ -97,7 +100,7 @@ main(int argc, char *argv[])
goto done;
}
- while ((ch = getopt(argc, argv, "Ff:h:i")) != -1) {
+ while ((ch = getopt(argc, argv, "Ff:h:irt:u:")) != -1) {
switch (ch) {
case 'F':
force = 1;
@@ -121,6 +124,23 @@ main(int argc, char *argv[])
case 'i':
index = 1;
break;
+ case 'r':
+ rss = 1;
+ break;
+ case 't':
+ title = strdup(optarg);
+ if (title == NULL) {
+ error = ssnail_error_from_errno("title");
+ goto done;
+ }
+ break;
+ case 'u':
+ url = strdup(optarg);
+ if (url == NULL) {
+ error = ssnail_error_from_errno("url");
+ goto done;
+ }
+ break;
default:
usage();
}
@@ -130,6 +150,9 @@ main(int argc, char *argv[])
LIST_INIT(&head); /* init the linked list */
+ /* title and usage are mandatory */
+ if (!title || !url)
+ usage();
/* src and dst dir are mandatory. */
if (argc < 2)
usage();
@@ -147,9 +170,12 @@ main(int argc, char *argv[])
error = write_html(ap, header_tpl, footer_tpl);
if (error)
goto done;
+ index = 1;
+ rss = 1;
}
if (strcmp(ap->type, "article") == 0) {
add_index_entry(&index_listing, ap);
+ add_rss_entry(&rss_listing, ap, url);
}
}
@@ -161,12 +187,20 @@ main(int argc, char *argv[])
goto done;
}
error = write_html(ip, header_tpl, footer_tpl);
+ if (error)
+ goto done;
+ }
+
+ if (rss || force) {
+ printf("Generate rss ... \n");
+ error = write_rss(argv[1], rss_listing, title, url);
}
done:
free(header_tpl);
free(footer_tpl);
free(index_listing);
+ free(rss_listing);
free_article(ip);
free_articleq(&head);
@@ -562,3 +596,91 @@ init_article(void)
return a;
}
+
+static void
+add_rss_entry(char **rss_listing, struct article *a, char *url)
+{
+ if (!rss_listing || !a)
+ return;
+
+ struct tm timeinfo;
+ char *content = NULL, *html_file = NULL,
+ *link = NULL, pub_date[LONG_DATE_Z];
+ const char *entry_format =
+ "%s<item>\n"
+ "<guid>%s</guid>\n"
+ "<link>%s</link>\n"
+ "<author>%s</author>\n"
+ "<title>%s</title>\n"
+ "<pubDate>%s</pubDate>\n"
+ "<description>\n%s\n</description>\n"
+ "</item>\n";
+
+ if (strptime(a->date, "%Y-%m-%d", &timeinfo) == NULL)
+ goto out;
+
+ /*
+ * we don't keep the hour and tz values on the markdown metadata, so set
+ * it to 00h GMT. Which will never be too off from reality.
+ */
+ if (strftime(pub_date, LONG_DATE_Z, "%a, %d %b %Y 00:00:00 GMT", &timeinfo) == 0)
+ goto out;
+
+ content = strndup(a->html_content, a->htmlz);
+ html_file = strstr(a->dst_path, "/") + 1;
+ if (html_file)
+ link = build_full_path(url, html_file);
+
+ if (link && content)
+ asprintf(rss_listing, entry_format, *rss_listing,
+ link, link, a->author, a->title, pub_date, content);
+
+out:
+ free(link);
+ free(content);
+}
+
+static const struct ssnail_error *
+write_rss(char *dst_path, char *rss_listing, char *title, char *url)
+{
+ const struct ssnail_error *error = NULL;
+ struct tm *timeinfo;
+ time_t now;
+ FILE *fout;
+ char *rss_path = NULL, *pub_date = NULL;
+ char *rss_format =
+ "<rss version=\"2.0\"\n"
+ "<channel>\n"
+ "<title>%s</title>\n"
+ "<link>%s</link>\n"
+ "<lastBuildDate>%s</lastBuildDate>\n"
+ "%s\n"
+ "</channel>\n"
+ "</rss>\n";
+
+ time(&now);
+ timeinfo = localtime(&now);
+ pub_date = malloc(LONG_DATE_Z);
+ if (strftime(pub_date, LONG_DATE_Z, "%a, %d %b %Y %H:%M:%S %z", timeinfo) == 0)
+ goto out;
+
+ if ((rss_path = build_full_path(dst_path, "rss.xml")) == NULL)
+ goto out;
+
+ if ((fout = fopen(rss_path, "w")) == NULL) {
+ error = ssnail_error_from_errno("openw rss");
+ goto out;
+ }
+
+ int ret = fprintf(fout, rss_format, title, url, pub_date, rss_listing);
+ if (ret < 0) {
+ error = ssnail_error_from_errno("write rss");
+ goto out;
+ }
+
+ if (fclose(fout) != 0)
+ error = ssnail_error_from_errno("close fout");
+
+out:
+ return error;
+}