diff --git a/zet.dpi.c b/zet.dpi.c
index f92f738..f174734 100644
--- a/zet.dpi.c
+++ b/zet.dpi.c
@@ -59,9 +59,15 @@ struct zet_search {
char *query;
};
+struct zet_mtime {
+ char *id;
+ int mtime;
+};
+
enum page {
PAGE_NEW,
PAGE_ALL,
+ PAGE_RECENT,
PAGE_HEADS,
PAGE_TAILS,
PAGE_ZET,
@@ -107,6 +113,14 @@ static int write_html_char(int fd, char c) {
return write_char(fd, c);
}
+static void write_err(int fd, const char *subject) {
+ int rc = dprintf(fd,
+ "\nError: %s: %s\n",
+ subject,
+ strerror(errno));
+ if (rc < 0) warnx("dprintf");
+}
+
static int write_html(int fd, const char *buf, size_t len) {
while (len > 0) {
// note: buf must null-terminated
@@ -141,6 +155,11 @@ static int write_topbar(int fd, enum page page, const char *id, const char *titl
rc |= write_buf(fd, "All");
if (page == PAGE_ALL) rc |= write_buf(fd, "");
+ rc |= write_buf(fd, " ");
+ if (page == PAGE_RECENT) rc |= write_buf(fd, "");
+ rc |= write_buf(fd, "Recent");
+ if (page == PAGE_RECENT) rc |= write_buf(fd, "");
+
rc |= write_buf(fd, " ");
if (page == PAGE_NEW) rc |= write_buf(fd, "");
rc |= write_buf(fd, "New");
@@ -221,6 +240,13 @@ static char *zet_get_title(const char *id, char *buf, size_t len) {
return buf;
}
+static int zet_stat(const char *id, struct stat *st) {
+ char path_buf[_POSIX_PATH_MAX];
+ ssize_t sz = snprintf(path_buf, sizeof(path_buf), "%s/%s", zet_dir, id);
+ if (sz < 0 || (size_t)sz >= sizeof(path_buf)) return -1;
+ return stat(path_buf, st);
+}
+
static int zet_has_links(const char *id) {
char path_buf[_POSIX_PATH_MAX];
ssize_t sz = snprintf(path_buf, sizeof(path_buf), "%s/%s", zet_dir, id);
@@ -426,6 +452,87 @@ static int dpi_serve_zet_all(int fd) {
return 0;
}
+static int cmp_zet_mtimes(const void *ptr1, const void *ptr2) {
+ const struct zet_mtime *zet_mtime1 = ptr1;
+ const struct zet_mtime *zet_mtime2 = ptr2;
+ return zet_mtime2->mtime - zet_mtime1->mtime;
+}
+
+static int dpi_serve_zet_recent(int fd) {
+ int rc, i;
+ struct zet_search zs;
+ int capacity = 0;
+ int count = 0;
+ struct zet_mtime *zets = NULL;
+ rc = zet_search_start(&zs, NULL, NULL);
+ if (rc < 0) return dpi_respond_err(fd, "Unable to list");
+ rc = dpi_send_header(fd, "text/html");
+ if (rc < 0) { warn("dpi_send_header"); goto cleanup; }
+ rc = dprintf(fd,
+ ""
+ "Notes - Recent"
+ ""
+ ""
+ "");
+ rc |= write_topbar(fd, PAGE_RECENT, NULL, NULL);
+ rc |= write_buf(fd, "");
+ if (rc < 0) { warn("write"); goto cleanup; }
+ const char *id;
+ for (i = 0;; i++) {
+ struct stat st;
+ rc = zet_search_next(&zs, &id);
+ if (rc == 0 && id == NULL) break;
+ if (rc == 0) rc = zet_stat(id, &st);
+ if (rc == 0 && i >= capacity) {
+ if (capacity == 0) capacity = 256;
+ else capacity *= 2;
+ void *new_zets = reallocarray(zets, capacity, sizeof *zets);
+ if (new_zets == NULL) rc = -1;
+ else zets = new_zets;
+ }
+
+ if (rc < 0) {
+ write_err(fd, "list");
+ goto cleanup;
+ }
+ zets[i].mtime = st.st_mtime;
+ zets[i].id = strdup(id);
+ count++;
+ }
+
+ qsort(zets, count, sizeof(*zets), cmp_zet_mtimes);
+ static int limit = 50;
+ if (limit > count) limit = count;
+
+ for (i = 0; i < limit; i++) {
+ id = zets[i].id;
+ char title_buf[128];
+ char *title = zet_get_title(id, title_buf, sizeof(title_buf));
+ if (title == NULL) {
+ write_err(fd, "get_title");
+ goto cleanup;
+ }
+ rc = dprintf(fd, "- ", id);
+ rc |= write_html(fd, title, strlen(title));
+ rc |= write_buf(fd, "
");
+ if (rc < 0) { warnx("write"); goto cleanup; }
+ }
+
+ rc = dprintf(fd, "
");
+ if (rc < 0) warn("dprintf");
+
+cleanup:
+ for (i = 0; i < count; i++) {
+ free(zets[i].id);
+ }
+ free(zets);
+
+ rc = zet_search_close(&zs);
+ if (rc < 0) warn("closedir");
+ close(fd);
+ return 0;
+}
+
static int dpi_serve_zet_heads(int fd) {
int rc;
struct zet_search zs;
@@ -800,6 +907,7 @@ static int dpi_serve_zet(int fd, char *path) {
if (!strcmp(path, "/")) return dpi_serve_zet_heads(fd);
if (!strcmp(path, "/tails")) return dpi_serve_zet_tails(fd);
if (!strcmp(path, "/all")) return dpi_serve_zet_all(fd);
+ if (!strcmp(path, "/recent")) return dpi_serve_zet_recent(fd);
if (!strcmp(path, "/search")) return dpi_serve_zet_search(fd, query);
if (!strcmp(path, "/new")) return dpi_serve_zet_new(fd);