about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-07-10 14:54:45 -0400
committerJune McEnroe <june@causal.agency>2020-07-10 14:54:45 -0400
commit3926094bc216277ff6c58e6e9efba64fc7af91da (patch)
tree55362740094489c3e59fbc125ed181dd18cf0077
parentAdd -l and -r options (diff)
downloadscooper-3926094bc216277ff6c58e6e9efba64fc7af91da.tar.gz
scooper-3926094bc216277ff6c58e6e9efba64fc7af91da.zip
Implement partial table output of events
This should work for both events and search pages.
-rw-r--r--default.css17
-rw-r--r--events.c19
-rw-r--r--html.c103
-rw-r--r--server.h34
4 files changed, 167 insertions, 6 deletions
diff --git a/default.css b/default.css
index 449132f..40d9e88 100644
--- a/default.css
+++ b/default.css
@@ -36,7 +36,24 @@ nav form {
 	margin-top: 1em;
 }
 
+td.nick {
+	text-align: right;
+}
+tr.privmsg td.nick span::before {
+	content: '<';
+}
+tr.privmsg td.nick span::after {
+	content: '>';
+}
+tr.action td.nick span::before {
+	content: '* ';
+}
+tr.notice td.nick span::before, tr.notice td.nick span::after {
+	content: '-';
+}
+
 footer {
+	margin-top: 1em;
 	display: flex;
 	flex-wrap: wrap;
 	justify-content: space-between;
diff --git a/events.c b/events.c
index 7962ab3..32e94c2 100644
--- a/events.c
+++ b/events.c
@@ -107,7 +107,8 @@ enum kcgi_err pageEvents(struct kreq *req) {
 		|| khttp_body(req)
 		|| khtml_open(&html, req, KHTML_PRETTY)
 		|| htmlHead(&html, context)
-		|| htmlNav(&html, network, context);
+		|| htmlNav(&html, network, context)
+		|| khtml_elem(&html, KELEM_TABLE);
 	if (error) return error;
 
 	sqlite3_stmt *events = stmt.eventsAfter;
@@ -121,11 +122,17 @@ enum kcgi_err pageEvents(struct kreq *req) {
 
 	int result;
 	while (SQLITE_ROW == (result = sqlite3_step(events))) {
-		const char *msg = (const char *)sqlite3_column_text(events, 7);
-		if (!msg) continue;
-		error = 0
-			|| khtml_puts(&html, msg)
-			|| khtml_elem(&html, KELEM_BR);
+		struct Event event = {
+			.event = sqlite3_column_int64(events, 0),
+			.time = sqlite3_column_int64(events, 1),
+			.type = sqlite3_column_int(events, 2),
+			.nick = (const char *)sqlite3_column_text(events, 3),
+			.user = (const char *)sqlite3_column_text(events, 4),
+			.host = (const char *)sqlite3_column_text(events, 5),
+			.target = (const char *)sqlite3_column_text(events, 6),
+			.message = (const char *)sqlite3_column_text(events, 7),
+		};
+		error = htmlEvent(&html, event);
 		if (error) break;
 	}
 	if (result != SQLITE_DONE) errx(EX_SOFTWARE, "%s", sqlite3_errmsg(db));
diff --git a/html.c b/html.c
index 6141514..9f929e6 100644
--- a/html.c
+++ b/html.c
@@ -15,9 +15,11 @@
  */
 
 #include <err.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sysexits.h>
+#include <time.h>
 
 #include "server.h"
 
@@ -168,3 +170,104 @@ enum kcgi_err htmlFooter(struct khtmlreq *html) {
 		|| khtml_puts(html, "Columns")
 		|| khtml_closeto(html, 0);
 }
+
+static enum kcgi_err eventTime(struct khtmlreq *html, struct Event event) {
+	char time[sizeof("0000-00-00 00:00:00")];
+	strftime(time, sizeof(time), "%F %T", gmtime(&event.time));
+
+	char *base = NULL;
+	if (event.network && event.context) {
+		base = khttp_urlpart(
+			NULL, NULL, Pages[Events],
+			Keys[Network].name, event.network,
+			Keys[Context].name, event.context,
+			Keys[After].name, time,
+			NULL
+		);
+		if (!base) err(EX_OSERR, "khttp_urlpart");
+	}
+	char *href = NULL;
+	asprintf(&href, "%s#%" PRId64, (base ? base : ""), event.event);
+	if (!href) err(EX_OSERR, "asprintf");
+	if (base) free(base);
+
+	enum kcgi_err error = 0
+		|| khtml_attr(html, KELEM_TD, KATTR_CLASS, "time", KATTR__MAX)
+		|| khtml_attr(html, KELEM_A, KATTR_HREF, href, KATTR__MAX)
+		|| khtml_attr(html, KELEM_TIME, KATTR_DATETIME, time, KATTR__MAX)
+		|| khtml_puts(html, time)
+		|| khtml_closeelem(html, 3);
+
+	free(href);
+	return error;
+}
+
+static enum kcgi_err eventNetwork(struct khtmlreq *html, struct Event event) {
+	if (!event.network) return KCGI_OK;
+	char *href = khttp_urlpart(
+		NULL, NULL, Pages[Contexts],
+		Keys[Network].name, event.network,
+		NULL
+	);
+	if (!href) err(EX_OSERR, "khttp_urlpart");
+	enum kcgi_err error = 0
+		|| khtml_attr(html, KELEM_TD, KATTR_CLASS, "network", KATTR__MAX)
+		|| khtml_attr(html, KELEM_A, KATTR_HREF, href, KATTR__MAX)
+		|| khtml_puts(html, event.network)
+		|| khtml_closeelem(html, 2);
+	free(href);
+	return error;
+}
+
+static enum kcgi_err eventContext(struct khtmlreq *html, struct Event event) {
+	if (!event.network || !event.context) return KCGI_OK;
+	char *href = khttp_urlpart(
+		NULL, NULL, Pages[Events],
+		Keys[Network].name, event.network,
+		Keys[Context].name, event.context,
+		NULL
+	);
+	if (!href) err(EX_OSERR, "khttp_urlpart");
+	enum kcgi_err error = 0
+		|| khtml_attr(html, KELEM_TD, KATTR_CLASS, "context", KATTR__MAX)
+		|| khtml_attr(html, KELEM_A, KATTR_HREF, href, KATTR__MAX)
+		|| khtml_puts(html, event.context)
+		|| khtml_closeelem(html, 2);
+	free(href);
+	return error;
+}
+
+static enum kcgi_err eventNick(struct khtmlreq *html, struct Event event) {
+	char *mask = NULL;
+	asprintf(&mask, "%s!%s@%s", event.nick, event.user, event.host);
+	if (!mask) err(EX_OSERR, "asprintf");
+	enum kcgi_err error = 0
+		|| khtml_attr(html, KELEM_TD, KATTR_CLASS, "nick", KATTR__MAX)
+		|| khtml_attr(html, KELEM_SPAN, KATTR_TITLE, mask, KATTR__MAX)
+		|| khtml_puts(html, event.nick)
+		|| khtml_closeelem(html, 2);
+	free(mask);
+	return error;
+}
+
+static const char *Types[TypesLen] = {
+#define X(id, name) [id] = name,
+	ENUM_TYPE
+#undef X
+};
+
+enum kcgi_err htmlEvent(struct khtmlreq *html, struct Event event) {
+	const char *type = (event.type < TypesLen ? Types[event.type] : "unknown");
+	return 0
+		|| khtml_attrx(
+			html, KELEM_TR,
+			KATTR_ID, KATTRX_INT, event.event,
+			KATTR_CLASS, KATTRX_STRING, type,
+			KATTR__MAX
+		)
+		|| eventTime(html, event)
+		|| eventNetwork(html, event)
+		|| eventContext(html, event)
+		|| eventNick(html, event)
+		|| khtml_closeelem(html, 1);
+}
diff --git a/server.h b/server.h
index ba08a89..bb9bc60 100644
--- a/server.h
+++ b/server.h
@@ -33,6 +33,39 @@
 
 enum { DatabaseVersion = 4 };
 
+#define ENUM_TYPE \
+	X(Privmsg, "privmsg") \
+	X(Notice, "notice") \
+	X(Action, "action") \
+	X(Join, "join") \
+	X(Part, "part") \
+	X(Quit, "quit") \
+	X(Kick, "kick") \
+	X(Nick, "nick") \
+	X(Topic, "topic") \
+	X(Ban, "ban") \
+	X(Unban, "unban")
+
+enum Type {
+#define X(id, name) id,
+	ENUM_TYPE
+#undef X
+	TypesLen,
+};
+
+struct Event {
+	int64_t event;
+	time_t time;
+	const char *network;
+	const char *context;
+	enum Type type;
+	const char *nick;
+	const char *user;
+	const char *host;
+	const char *target;
+	const char *message;
+};
+
 extern sqlite3 *db;
 
 extern const char *NetworksQuery;
@@ -143,3 +176,4 @@ enum kcgi_err htmlNav(
 	struct khtmlreq *html, const char *network, const char *context
 );
 enum kcgi_err htmlFooter(struct khtmlreq *html);
+enum kcgi_err htmlEvent(struct khtmlreq *html, struct Event event);