summary refs log blame commit diff stats
path: root/html.c
blob: fa83f2cf065f4910d110968e0cf8c3e46f919112 (plain) (tree)































































































































































































































































                                                                                                                                                      
#include <sys/stat.h>
#include <sys/types.h>

#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#include <gemtext.h>

#include "gemlog.h"

/* TODO: allow user to specify custom header/footer */
#define HTML_HEADER_BEGIN "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">"
#define HTML_HEADER_END   "</head><body>"
#define HTML_FOOTER       "</body></html>"

static int
gemlog_write_html_text(struct gemtext *text, int fd)
{
	if (write(fd, "<p>", strlen("<p>")) == -1)
		return -1;
	if (write(fd, ((struct gemtext_text *)text)->text, strlen(((struct gemtext_text *)text)->text)) == -1)
		return -1;
	if (write(fd, "</p>\n", strlen("</p>\n")) == -1)
		return -1;
	return 0;
}

static int
gemlog_write_html_link(struct gemtext *text, int fd)
{
	if (write(fd, "<p><a href=\"", strlen("<p><a href=\"")) == -1)
		return -1;
	if (write(fd, ((struct gemtext_link *)text)->link, strlen(((struct gemtext_link *)text)->link)) == -1)
		return -1;
	if (write(fd, "\">", strlen("\">")) == -1)
		return -1;
	if (((struct gemtext_link *)text)->name) {
		if (write(fd, ((struct gemtext_link *)text)->name, strlen(((struct gemtext_link *)text)->name)) == -1)
			return -1;
	}
	if (write(fd, "</a></p>\n", strlen("</a></p>\n")) == -1)
		return -1;
	return 0;
}

static int
gemlog_write_html_pre(struct gemtext *text, int fd)
{
	if (write(fd, "<p><pre>", strlen("<p><pre>")) == -1)
		return -1;
	if (write(fd, ((struct gemtext_pre *)text)->text, strlen(((struct gemtext_pre *)text)->text)) == -1)
		return -1;
	if (write(fd, "</pre></p>\n", strlen("</pre></p>\n")) == -1)
		return -1;
	return 0;
}

static int
gemlog_write_html_h1(struct gemtext *text, int fd)
{
	if (write(fd, "<h1>", strlen("<h1>")) == -1)
		return -1;
	if (write(fd, ((struct gemtext_h1 *)text)->text, strlen(((struct gemtext_h1 *)text)->text)) == -1)
		return -1;
	if (write(fd, "</h1>\n", strlen("</h1>\n")) == -1)
		return -1;
	return 0;
}

static int
gemlog_write_html_h2(struct gemtext *text, int fd)
{
	if (write(fd, "<h2>", strlen("<h2>")) == -1)
		return -1;
	if (write(fd, ((struct gemtext_h2 *)text)->text, strlen(((struct gemtext_h2 *)text)->text)) == -1)
		return -1;
	if (write(fd, "</h2>\n", strlen("</h2>\n")) == -1)
		return -1;
	return 0;
}

static int
gemlog_write_html_h3(struct gemtext *text, int fd)
{
	if (write(fd, "<h3>", strlen("<h3>")) == -1)
		return -1;
	if (write(fd, ((struct gemtext_h3 *)text)->text, strlen(((struct gemtext_h3 *)text)->text)) == -1)
		return -1;
	if (write(fd, "</h3>\n", strlen("</h3>\n")) == -1)
		return -1;
	return 0;
}

static int
gemlog_write_html_ul(struct gemtext *text, int fd)
{
	if (write(fd, "<li>", strlen("<li>")) == -1)
		return -1;
	if (write(fd, ((struct gemtext_ul *)text)->text, strlen(((struct gemtext_ul *)text)->text)) == -1)
		return -1;
	if (write(fd, "</li>\n", strlen("</li>\n")) == -1)
		return -1;
	return 0;
}

static int
gemlog_write_html_qt(struct gemtext *text, int fd)
{
	if (write(fd, "<blockquote>", strlen("<blockquote>")) == -1)
		return -1;
	if (write(fd, ((struct gemtext_qt *)text)->text, strlen(((struct gemtext_qt *)text)->text)) == -1)
		return -1;
	if (write(fd, "</blockquote>\n", strlen("</blockquote>\n")) == -1)
		return -1;
	return 0;
}

int
gemlog_write_html(struct gemlog_entry **feed, const char *path)
{
	int i;
	int x;
	int ulindicator;
	int fd;
	char pathbuf[PATH_MAX+1];
	char fmtbuf[PATH_MAX+1];

	if (mkdir(path, 0755) == -1) {
		if (errno != EEXIST)
			return -1;
	}

	for (i = 0; feed[i] != NULL; i++) {
		strlcpy(pathbuf, path, sizeof(pathbuf));
		strlcat(pathbuf, "/", sizeof(pathbuf));
		snprintf(fmtbuf, sizeof(fmtbuf), "%d", feed[i]->date.tm_year+1900);
		strlcat(pathbuf, fmtbuf, sizeof(pathbuf));
		if (mkdir(pathbuf, 0755) == -1) {
			if (errno != EEXIST)
				return -1;
		}

		strlcat(pathbuf, "/", sizeof(pathbuf));
		snprintf(fmtbuf, sizeof(fmtbuf), "%d", feed[i]->date.tm_mon+1);
		strlcat(pathbuf, fmtbuf, sizeof(pathbuf));
		if (mkdir(pathbuf, 0755) == -1) {
			if (errno != EEXIST)
				return -1;
		}

		strlcat(pathbuf, "/", sizeof(pathbuf));
		snprintf(fmtbuf, sizeof(fmtbuf), "%d", feed[i]->date.tm_mday);
		strlcat(pathbuf, fmtbuf, sizeof(pathbuf));
		if (mkdir(pathbuf, 0755) == -1) {
			if (errno != EEXIST)
				return -1;
		}

		strlcat(pathbuf, "/", sizeof(pathbuf));
		snprintf(fmtbuf, sizeof(fmtbuf), "%d", feed[i]->date.tm_hour);
		strlcat(pathbuf, fmtbuf, sizeof(pathbuf));
		if (mkdir(pathbuf, 0755) == -1) {
			if (errno != EEXIST)
				return -1;
		}

		strlcat(pathbuf, "/", sizeof(pathbuf));
		strlcat(pathbuf, GEMLOG_CONTENT_HTML_FILENAME, sizeof(pathbuf));
		fd = open(pathbuf, O_WRONLY|O_CREAT|O_TRUNC);
		if (fd == -1)
			return -1;
		if (chmod(pathbuf, 0644) == -1) {
			close(fd);
			return -1;
		}

		/* write header */
		if (write(fd, HTML_HEADER_BEGIN, strlen(HTML_HEADER_BEGIN)) == -1) {
			close(fd);
			return -1;
		}
		if (write(fd, "<title>", strlen("<title>")) == -1) {
			close(fd);
			return -1;
		}
		if (write(fd, feed[i]->title, strlen(feed[i]->title)) == -1) {
			close(fd);
			return -1;
		}
		if (write(fd, "</title>", strlen("</title>")) == -1) {
			close(fd);
			return -1;
		}
		if (write(fd, HTML_HEADER_END, strlen(HTML_HEADER_END)) == -1) {
			close(fd);
			return -1;
		}

		ulindicator = 0;
		for (x = 0; feed[i]->content[x] != NULL; x++) {
			if (ulindicator) {
				if (gemtext_type(feed[i]->content[x]) != GEMTEXT_UL) {
					if (write(fd, "</ul>\n", strlen("</ul>\n")) == -1) {
						close(fd);
						return -1;
					}
					ulindicator = 0;
				}
			}
			switch (gemtext_type(feed[i]->content[x])) {
			case GEMTEXT_TEXT:
				gemlog_write_html_text(feed[i]->content[x], fd);
				break;
			case GEMTEXT_LINK:
				gemlog_write_html_link(feed[i]->content[x], fd);
				break;
			case GEMTEXT_PRE:
				gemlog_write_html_pre(feed[i]->content[x], fd);
				break;
			case GEMTEXT_H1:
				gemlog_write_html_h1(feed[i]->content[x], fd);
				break;
			case GEMTEXT_H2:
				gemlog_write_html_h2(feed[i]->content[x], fd);
				break;
			case GEMTEXT_H3:
				gemlog_write_html_h3(feed[i]->content[x], fd);
				break;
			case GEMTEXT_UL:
				if (!ulindicator) {
					if (write(fd, "<ul>\n", strlen("<ul>\n")) == -1) {
						close(fd);
						return -1;
					}
					ulindicator = 1;
				}
				gemlog_write_html_ul(feed[i]->content[x], fd);
				break;
			case GEMTEXT_QT:
				gemlog_write_html_qt(feed[i]->content[x], fd);
				break;
			default:
				close(fd);
				return -1;
			}
		}
		close(fd);
	}

	return 0;
}