about summary refs log tree commit diff
path: root/events.c
diff options
context:
space:
mode:
Diffstat (limited to 'events.c')
-rw-r--r--events.c96
1 files changed, 56 insertions, 40 deletions
diff --git a/events.c b/events.c
index e018087..35e2c5b 100644
--- a/events.c
+++ b/events.c
@@ -15,6 +15,7 @@
  */
 
 #include <err.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sysexits.h>
@@ -22,32 +23,21 @@
 
 #include "server.h"
 
-static enum kcgi_err redirect(struct kreq *req, struct Scope scope) {
-	struct tm *tm = gmtime(&(time_t) { time(NULL) });
-	if (!tm) err(EX_OSERR, "gmtime");
-
-	char time[sizeof("0000-00-00T00:00:00")];
-	strftime(time, sizeof(time), "%FT%T", tm);
-
-	char *url = khttp_urlpart(
-		NULL, NULL, Pages[Events],
-		Keys[Network].name, scope.network,
-		Keys[Context].name, scope.context,
-		Keys[Before].name, time,
-		NULL
-	);
-	enum kcgi_err error = httpRedirect(req, url);
-	free(url);
-	return error;
+int eventsGap = 3600;
+int eventsOverlap = 15;
+int eventsLimit = 50;
+
+static const char *timestamp(time_t time) {
+	static char stamp[sizeof("0000-00-00T00:00:00")];
+	strftime(stamp, sizeof(stamp), "%FT%T", gmtime(&time));
+	return stamp;
 }
 
 static enum kcgi_err
 dateForm(struct khtmlreq *html, struct Scope scope, const char *_time) {
 	struct tm tm = {0};
 	if (!strptime(_time, "%F", &tm)) {
-		struct tm *now = gmtime(&(time_t) { time(NULL) });
-		if (!now) err(EX_OSERR, "gmtime");
-		tm = *now;
+		tm = *gmtime(&(time_t) { time(NULL) });
 	}
 	char date[sizeof("0000-00-00")];
 	strftime(date, sizeof(date), "%F", &tm);
@@ -58,20 +48,7 @@ dateForm(struct khtmlreq *html, struct Scope scope, const char *_time) {
 			KATTR_ACTION, Pages[Events],
 			KATTR__MAX
 		)
-		|| khtml_attr(
-			html, KELEM_INPUT,
-			KATTR_TYPE, "hidden",
-			KATTR_NAME, Keys[Network].name,
-			KATTR_VALUE, scope.network,
-			KATTR__MAX
-		)
-		|| khtml_attr(
-			html, KELEM_INPUT,
-			KATTR_TYPE, "hidden",
-			KATTR_NAME, Keys[Context].name,
-			KATTR_VALUE, scope.context,
-			KATTR__MAX
-		)
+		|| htmlScopeFields(html, scope)
 		|| khtml_attr(
 			html, KELEM_INPUT,
 			KATTR_TYPE, "date",
@@ -134,12 +111,24 @@ const char *EventsBeforeQuery = SQL(
 	ORDER BY time, event;
 );
 
-enum kcgi_err pageEvents(struct kreq *req) {
-	struct Scope scope = htmlScope(req);
+enum kcgi_err eventsPage(struct kreq *req) {
+	struct Scope scope = pageScope(req);
 	if (!scope.network || !scope.context) return httpFail(req, KHTTP_400);
+
 	if (!req->fieldmap[After] && !req->fieldmap[Before]) {
-		return redirect(req, scope);
+		char *url = khttp_urlpart(
+			NULL, NULL, Pages[Events],
+			Keys[Network].name, scope.network,
+			Keys[Context].name, scope.context,
+			Keys[Before].name, timestamp(time(NULL)),
+			NULL
+		);
+		if (!url) err(EX_OSERR, "khttp_urlpart");
+		enum kcgi_err error = httpRedirect(req, url);
+		free(url);
+		return error;
 	}
+
 	const char *time = req->fieldmap[Before]
 		? req->fieldmap[Before]->parsed.s
 		: req->fieldmap[After]->parsed.s;
@@ -164,11 +153,12 @@ enum kcgi_err pageEvents(struct kreq *req) {
 	dbBindText(events, ":network", scope.network);
 	dbBindText(events, ":context", scope.context);
 	dbBindText(events, ":time", time);
-	dbBindInt(events, ":public", pagePublic);
-	dbBindInt(events, ":limit", pageLimit);
+	dbBindInt(events, ":public", contextsPublic);
+	dbBindInt(events, ":limit", eventsLimit);
 
+	int rows;
 	int result;
-	while (SQLITE_ROW == (result = sqlite3_step(events))) {
+	for (rows = 0; SQLITE_ROW == (result = sqlite3_step(events)); ++rows) {
 		int i = 0;
 		struct Event event = {0};
 		event.event = sqlite3_column_int64(events, i++);
@@ -179,6 +169,32 @@ enum kcgi_err pageEvents(struct kreq *req) {
 		event.host = sqlite3_column_text(events, i++);
 		event.target = sqlite3_column_text(events, i++);
 		event.message = sqlite3_column_text(events, i++);
+
+		if (!rows) {
+			char *base = khttp_urlpart(
+				NULL, NULL, Pages[Events],
+				Keys[Network].name, scope.network,
+				Keys[Context].name, scope.context,
+				Keys[Before].name, timestamp(event.time + eventsOverlap),
+				NULL
+			);
+			if (!base) err(EX_OSERR, "khttp_urlpart");
+
+			char *href = NULL;
+			asprintf(&href, "%s#%" PRId64, base, event.event);
+			if (!href) err(EX_OSERR, "asprintf");
+			free(base);
+
+			error = 0
+				|| khtml_elem(&html, KELEM_TR)
+				|| khtml_attr(&html, KELEM_TH, KATTR_COLSPAN, "3", KATTR__MAX)
+				|| khtml_attr(&html, KELEM_A, KATTR_HREF, href, KATTR__MAX)
+				|| khtml_puts(&html, "Earlier messages")
+				|| khtml_closeelem(&html, 3);
+			free(href);
+			if (error) return error;
+		}
+
 		error = htmlEvent(&html, scope, event);
 		if (error) return error;
 	}