diff --git a/zet.dpi.c b/zet.dpi.c index fa13a1d..9db8db6 100644 --- a/zet.dpi.c +++ b/zet.dpi.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,7 @@ enum page { PAGE_NEW, PAGE_ALL, PAGE_HEADS, + PAGE_TAILS, PAGE_ZET, PAGE_SEARCH, }; @@ -129,6 +131,11 @@ static int write_topbar(int fd, enum page page, const char *id, const char *titl rc |= write_buf(fd, "Heads"); if (page == PAGE_HEADS) rc |= write_buf(fd, ""); + rc |= write_buf(fd, " "); + if (page == PAGE_TAILS) rc |= write_buf(fd, ""); + rc |= write_buf(fd, "Tails"); + if (page == PAGE_TAILS) rc |= write_buf(fd, ""); + rc |= write_buf(fd, " "); if (page == PAGE_ALL) rc |= write_buf(fd, ""); rc |= write_buf(fd, "All"); @@ -214,6 +221,50 @@ static char *zet_get_title(const char *id, char *buf, size_t len) { return buf; } +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); + if (sz < 0 || (size_t)sz >= sizeof(path_buf)) return -1; + int fd = open(path_buf, O_RDONLY); + if (fd < 0) return -1; + struct stat st; + int rc = fstat(fd, &st); + if (rc < 0) goto error; + char *buf = malloc(st.st_size+1); + rc = read_all(fd, buf, st.st_size); + if (rc < 0) goto error; + buf[st.st_size] = '\0'; + char *str = buf; + bool found_link = false; + while ((str = strstr(str, "ยง"))) { + int i; + bool matched_id_format = true; + str += sigil_size; + for (i = 0; i < id_length; i++) { + if (!isxdigit(str[i])) { + matched_id_format = false; + str += i; + break; + } + } + if (matched_id_format) { + found_link = true; + break; + } + } + free(buf); + close(fd); + return found_link ? 0 : 1; + + int err; +error: + err = errno; + free(buf); + close(fd); + errno = err; + return -1; +} + static char *zet_get_buf_title(const struct buf *link, char *buf, size_t len) { char id_buf[128]; strncpy(id_buf, link->data, link->size); @@ -440,6 +491,60 @@ static int dpi_serve_zet_heads(int fd) { return 0; } +static int dpi_serve_zet_tails(int fd) { + int rc; + struct zet_search zs; + 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"); close(fd); return 0; } + rc = dprintf(fd, + "" + "Notes - Tails" + "" + "" + ""); + rc |= write_topbar(fd, PAGE_HEADS, NULL, NULL); + rc |= write_buf(fd, "
    "); + if (rc < 0) { warn("write"); close(fd); return 0; } + const char *id; + while (1) { + rc = zet_search_next(&zs, &id); + if (rc < 0) { + rc = dprintf(fd, + "\nError: %s\n", + strerror(errno)); + if (rc < 0) warnx("dprintf"); + close(fd); + return 0; + } + if (id == NULL) break; + + int has_link = zet_has_links(id); + if (has_link < 0) warn("zet_has_link"); + if (has_link == 0) continue; + + char title_buf[128]; + char *title = zet_get_title(id, title_buf, sizeof(title_buf)); + if (title == NULL) { + warn("zet_get_title"); + title = title_buf; + strncpy(title, id, sizeof(title)-1); + title[sizeof(title)-1] = '\0'; + return 0; + } + rc = dprintf(fd, "
  • ", id); + rc |= write_html(fd, title, strlen(title)); + rc |= write_buf(fd, "
  • "); + if (rc < 0) { warnx("write"); close(fd); return 0; } + } + rc = dprintf(fd, "
"); + if (rc < 0) { warn("dprintf"); close(fd); return 0; } + rc = zet_search_close(&zs); + if (rc < 0) warn("closedir"); + close(fd); + return 0; +} static void unescape(char *buf, size_t len, const char *str) { struct buf *ob = bufnew(1024); @@ -693,6 +798,7 @@ static int dpi_serve_zet(int fd, char *path) { parse_req_uri(path, &hash, &query); 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, "/search")) return dpi_serve_zet_search(fd, query); if (!strcmp(path, "/new")) return dpi_serve_zet_new(fd);