main
cel 5 years ago
parent 19ac6f7d78
commit 57c8c1d88a

@ -1,3 +1,5 @@
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
@ -50,12 +52,14 @@ struct http_request {
struct zet_search {
DIR *dir;
char *id;
char *query;
};
enum page {
PAGE_NEW,
PAGE_ALL,
PAGE_ZET,
PAGE_SEARCH,
};
static int count_lines_in(const char *str) {
@ -114,8 +118,8 @@ static int write_html(int fd, const char *buf, size_t len) {
return 0;
}
static int write_topbar(int fd, enum page page, const char *id) {
int rc = write_buf(fd, "<div>");
static int write_topbar(int fd, enum page page, const char *str) {
int rc = write_buf(fd, "<form action=\"search\">");
if (page == PAGE_ALL) rc |= write_buf(fd, "<strong>");
rc |= write_buf(fd, "<a href=\".\">All</a>");
@ -126,10 +130,19 @@ static int write_topbar(int fd, enum page page, const char *id) {
rc |= write_buf(fd, "<a href=\"new\">New</a>");
if (page == PAGE_NEW) rc |= write_buf(fd, "</strong>");
rc |= write_buf(fd, " <input name=q placeholder=Search");
if (page == PAGE_SEARCH) {
rc |= write_buf(fd, " value=\"");
rc |= write_html(fd, str, strlen(str));
rc |= write_buf(fd, "\"");
}
rc |= write_buf(fd, ">");
if (page == PAGE_ZET) {
rc |= dprintf(fd, " <strong><code><a href=\"%s\">§%s</a></code></strong>", id, id);
rc |= dprintf(fd, " <strong><code><a href=\"%s\">§%s</a></code></strong>", str, str);
}
rc |= write_buf(fd, "</div>");
rc |= write_buf(fd, "</form>");
return rc;
}
@ -233,10 +246,25 @@ static int zet_links_to(const char *id_from, const char *id_to) {
return rc;
}
static int zet_search_start(struct zet_search *zs, char *id) {
static int zet_matches_query(const char *id, const char *query) {
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 note_fd = open(path_buf, O_RDONLY);
if (note_fd < 0) return -1;
char *text = read_full(note_fd);
bool found = strcasestr(text, query) != NULL;
free(text);
return found ? 1 : 0;
}
static int zet_search_start(struct zet_search *zs, char *id, char *query) {
zs->dir = opendir(zet_dir);
if (zs->dir == NULL) return -1;
zs->id = id;
zs->query = query;
return 0;
}
@ -245,6 +273,7 @@ static int zet_search_next(struct zet_search *zs, const char **idp) {
struct dirent *ent;
const char *id;
char *const dest_id = zs->id;
char *const query = zs->query;
while (1) {
errno = 0;
ent = readdir(zs->dir);
@ -257,7 +286,12 @@ static int zet_search_next(struct zet_search *zs, const char **idp) {
if (id[0] == '.') continue;
if (strpbrk(id, "<>&\"~") != NULL) continue;
if (dest_id != NULL) {
rc = zet_links_to(id, zs->id);
rc = zet_links_to(id, dest_id);
if (rc < 0) return -1;
if (rc != 1) continue;
}
if (query != NULL) {
rc = zet_matches_query(id, query);
if (rc < 0) return -1;
if (rc != 1) continue;
}
@ -274,7 +308,7 @@ static int zet_search_close(struct zet_search *sz) {
static int dpi_serve_zet_index(int fd) {
int rc;
struct zet_search zs;
rc = zet_search_start(&zs, 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"); close(fd); return 0; }
@ -288,6 +322,72 @@ static int dpi_serve_zet_index(int fd) {
rc |= write_buf(fd, "<ul>");
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,
"\n<strong>Error</strong>: %s\n",
strerror(errno));
if (rc < 0) warnx("dprintf");
close(fd);
return 0;
}
if (id == NULL) break;
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, "<li><a href=\"%s\">", id);
rc |= write_html(fd, title, strlen(title));
rc |= write_buf(fd, "</a></li>");
if (rc < 0) { warnx("write"); close(fd); return 0; }
}
rc = dprintf(fd, "</ul></body></html>");
if (rc < 0) { warn("dprintf"); close(fd); return 0; }
rc = zet_search_close(&zs);
if (rc < 0) warn("closedir");
close(fd);
return 0;
}
static int dpi_serve_zet_search(int fd, char *qs) {
int rc;
struct zet_search zs;
char *query = NULL;
char *name = qs, *next_name;
while (name != NULL) {
char *value = strchr(name, '=');
if (value != NULL) *value++ = '\0';
next_name = strchr(value != NULL ? value : name, '&');
if (next_name != NULL) *next_name++ = '\0';
if (!strcmp(name, "q")) query = value;
name = next_name;
}
rc = zet_search_start(&zs, NULL, query);
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,
"<!doctype html><html><head>"
"<title>Notes</title>"
"<meta charset=utf-8>"
"</head>"
"<body>"
);
rc |= write_topbar(fd, PAGE_SEARCH, query);
rc |= write_buf(fd, "<ul>");
if (rc < 0) { warn("write"); close(fd); return 0; }
const char *id;
while (1) {
rc = zet_search_next(&zs, &id);
if (rc < 0) {
@ -350,10 +450,13 @@ static int dpi_serve_zet_new(int fd) {
}
static void parse_req_uri(char *path, char **hashp, char **queryp) {
char *hash = *hashp = strchr(path, '#');
char *hash = strchr(path, '#');
if (hash != NULL) *hash++ = '\0';
char *query = *queryp = strchr(path, '?');
*hashp = hash;
char *query = strchr(path, '?');
if (query != NULL) *query++ = '\0';
*queryp = query;
}
static int
@ -460,6 +563,7 @@ static int dpi_serve_zet(int fd, char *path) {
parse_req_uri(path, &hash, &query);
if (!strcmp(path, "/")) return dpi_serve_zet_index(fd);
if (!strcmp(path, "/search")) return dpi_serve_zet_search(fd, query);
if (!strcmp(path, "/new")) return dpi_serve_zet_new(fd);
char path_buf[_POSIX_PATH_MAX];
@ -542,7 +646,7 @@ static int dpi_serve_zet(int fd, char *path) {
if (rc < 0) warn("dprintf");
struct zet_search zs;
bool first = true;
rc = zet_search_start(&zs, id);
rc = zet_search_start(&zs, id, NULL);
if (rc < 0) warn("zet_search_start");
do {
const char *result_id;

Loading…
Cancel
Save