summary refs log tree commit diff
path: root/search.c
diff options
context:
space:
mode:
Diffstat (limited to 'search.c')
-rw-r--r--search.c83
1 files changed, 82 insertions, 1 deletions
diff --git a/search.c b/search.c
index c9a9044..767081b 100644
--- a/search.c
+++ b/search.c
@@ -21,6 +21,87 @@
 
 #include "server.h"
 
+const char *SearchQuery = SQL(
+	SELECT
+		events.event,
+		events.time,
+		contexts.network,
+		contexts.name,
+		events.type,
+		names.nick,
+		names.user,
+		names.host,
+		events.target,
+		highlight(search, 6, :highlight, :highlight)
+	FROM events
+	JOIN contexts USING (context)
+	JOIN names USING (name)
+	JOIN search ON search.rowid = events.event
+	WHERE coalesce(contexts.network = :network, true)
+		AND coalesce(contexts.name = :context, true)
+		AND coalesce(contexts.query = :query, true)
+		AND search MATCH :search
+	LIMIT :limit
+	OFFSET :offset;
+);
+
 enum kcgi_err pageSearch(struct kreq *req) {
-	return httpFail(req, KHTTP_501);
+	if (!req->fieldmap[Query]) {
+		return httpFail(req, KHTTP_400);
+	}
+	if (req->fieldmap[Context] && !req->fieldmap[Network]) {
+		return httpFail(req, KHTTP_400);
+	}
+	const char *query = req->fieldmap[Query]->parsed.s;
+
+	int64_t offset = 0;
+	const char *network = NULL;
+	const char *context = NULL;
+	if (req->fieldmap[Offset]) offset = req->fieldmap[Offset]->parsed.i;
+	if (req->fieldmap[Network]) network = req->fieldmap[Network]->parsed.s;
+	if (req->fieldmap[Context]) context = req->fieldmap[Context]->parsed.s;
+
+	enum kcgi_err error = httpHead(req, KHTTP_200, KMIME_TEXT_HTML);
+	if (req->method == KMETHOD_HEAD) return error;
+
+	struct khtmlreq html;
+	error = error
+		|| khttp_body(req)
+		|| khtml_open(&html, req, KHTML_PRETTY)
+		|| htmlHead(&html, query)
+		|| htmlNav(&html, network, context)
+		|| khtml_elem(&html, KELEM_TABLE);
+	if (error) return error;
+
+	dbBindText(stmt.search, ":highlight", "\26");
+	dbBindText(stmt.search, ":network", network);
+	dbBindText(stmt.search, ":context", context);
+	if (pagePublic) dbBindInt(stmt.search, ":query", false);
+	dbBindText(stmt.search, ":search", query);
+	dbBindInt(stmt.search, ":limit", pageLimit);
+	dbBindInt(stmt.search, ":offset", offset);
+
+	int result;
+	while (SQLITE_ROW == (result = sqlite3_step(stmt.search))) {
+		struct Event event = {
+			.event = sqlite3_column_int64(stmt.search, 0),
+			.time = sqlite3_column_int64(stmt.search, 1),
+			.network = (const char *)sqlite3_column_text(stmt.search, 2),
+			.context = (const char *)sqlite3_column_text(stmt.search, 3),
+			.type = sqlite3_column_int(stmt.search, 4),
+			.nick = (const char *)sqlite3_column_text(stmt.search, 5),
+			.user = (const char *)sqlite3_column_text(stmt.search, 6),
+			.host = (const char *)sqlite3_column_text(stmt.search, 7),
+			.target = (const char *)sqlite3_column_text(stmt.search, 8),
+			.message = (const char *)sqlite3_column_text(stmt.search, 9),
+		};
+		error = htmlEvent(&html, event);
+		if (error) break;
+	}
+	if (result != SQLITE_DONE) errx(EX_SOFTWARE, "%s", sqlite3_errmsg(db));
+	sqlite3_reset(stmt.search);
+
+	return error
+		|| htmlFooter(&html)
+		|| khtml_close(&html);
 }