|
|
@ -59,9 +59,15 @@ struct zet_search {
|
|
|
|
char *query;
|
|
|
|
char *query;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct zet_mtime {
|
|
|
|
|
|
|
|
char *id;
|
|
|
|
|
|
|
|
int mtime;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
enum page {
|
|
|
|
enum page {
|
|
|
|
PAGE_NEW,
|
|
|
|
PAGE_NEW,
|
|
|
|
PAGE_ALL,
|
|
|
|
PAGE_ALL,
|
|
|
|
|
|
|
|
PAGE_RECENT,
|
|
|
|
PAGE_HEADS,
|
|
|
|
PAGE_HEADS,
|
|
|
|
PAGE_TAILS,
|
|
|
|
PAGE_TAILS,
|
|
|
|
PAGE_ZET,
|
|
|
|
PAGE_ZET,
|
|
|
@ -107,6 +113,14 @@ static int write_html_char(int fd, char c) {
|
|
|
|
return write_char(fd, c);
|
|
|
|
return write_char(fd, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void write_err(int fd, const char *subject) {
|
|
|
|
|
|
|
|
int rc = dprintf(fd,
|
|
|
|
|
|
|
|
"\n<strong>Error</strong>: %s: %s\n",
|
|
|
|
|
|
|
|
subject,
|
|
|
|
|
|
|
|
strerror(errno));
|
|
|
|
|
|
|
|
if (rc < 0) warnx("dprintf");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int write_html(int fd, const char *buf, size_t len) {
|
|
|
|
static int write_html(int fd, const char *buf, size_t len) {
|
|
|
|
while (len > 0) {
|
|
|
|
while (len > 0) {
|
|
|
|
// note: buf must null-terminated
|
|
|
|
// 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, "<a href=\"all\">All</a>");
|
|
|
|
rc |= write_buf(fd, "<a href=\"all\">All</a>");
|
|
|
|
if (page == PAGE_ALL) rc |= write_buf(fd, "</strong>");
|
|
|
|
if (page == PAGE_ALL) rc |= write_buf(fd, "</strong>");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rc |= write_buf(fd, " ");
|
|
|
|
|
|
|
|
if (page == PAGE_RECENT) rc |= write_buf(fd, "<strong>");
|
|
|
|
|
|
|
|
rc |= write_buf(fd, "<a href=\"recent\">Recent</a>");
|
|
|
|
|
|
|
|
if (page == PAGE_RECENT) rc |= write_buf(fd, "</strong>");
|
|
|
|
|
|
|
|
|
|
|
|
rc |= write_buf(fd, " ");
|
|
|
|
rc |= write_buf(fd, " ");
|
|
|
|
if (page == PAGE_NEW) rc |= write_buf(fd, "<strong>");
|
|
|
|
if (page == PAGE_NEW) rc |= write_buf(fd, "<strong>");
|
|
|
|
rc |= write_buf(fd, "<a href=\"new\">New</a>");
|
|
|
|
rc |= write_buf(fd, "<a href=\"new\">New</a>");
|
|
|
@ -221,6 +240,13 @@ static char *zet_get_title(const char *id, char *buf, size_t len) {
|
|
|
|
return buf;
|
|
|
|
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) {
|
|
|
|
static int zet_has_links(const char *id) {
|
|
|
|
char path_buf[_POSIX_PATH_MAX];
|
|
|
|
char path_buf[_POSIX_PATH_MAX];
|
|
|
|
ssize_t sz = snprintf(path_buf, sizeof(path_buf), "%s/%s", zet_dir, id);
|
|
|
|
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;
|
|
|
|
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,
|
|
|
|
|
|
|
|
"<!doctype html><html><head>"
|
|
|
|
|
|
|
|
"<title>Notes - Recent</title>"
|
|
|
|
|
|
|
|
"<meta charset=utf-8>"
|
|
|
|
|
|
|
|
"</head>"
|
|
|
|
|
|
|
|
"<body>");
|
|
|
|
|
|
|
|
rc |= write_topbar(fd, PAGE_RECENT, NULL, NULL);
|
|
|
|
|
|
|
|
rc |= write_buf(fd, "<ul>");
|
|
|
|
|
|
|
|
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, "<li><a href=\"%s\">", id);
|
|
|
|
|
|
|
|
rc |= write_html(fd, title, strlen(title));
|
|
|
|
|
|
|
|
rc |= write_buf(fd, "</a></li>");
|
|
|
|
|
|
|
|
if (rc < 0) { warnx("write"); goto cleanup; }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rc = dprintf(fd, "</ul></body></html>");
|
|
|
|
|
|
|
|
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) {
|
|
|
|
static int dpi_serve_zet_heads(int fd) {
|
|
|
|
int rc;
|
|
|
|
int rc;
|
|
|
|
struct zet_search zs;
|
|
|
|
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, "/")) return dpi_serve_zet_heads(fd);
|
|
|
|
if (!strcmp(path, "/tails")) return dpi_serve_zet_tails(fd);
|
|
|
|
if (!strcmp(path, "/tails")) return dpi_serve_zet_tails(fd);
|
|
|
|
if (!strcmp(path, "/all")) return dpi_serve_zet_all(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, "/search")) return dpi_serve_zet_search(fd, query);
|
|
|
|
if (!strcmp(path, "/new")) return dpi_serve_zet_new(fd);
|
|
|
|
if (!strcmp(path, "/new")) return dpi_serve_zet_new(fd);
|
|
|
|
|
|
|
|
|
|
|
|