shithub: masto9

Download patch

ref: 8d24acf30776c1bee6b09af285d417bc66d87953
parent: cf0458c99c5d0d17e918f62c74b1343568eb3227
author: Julien Blanchard <julien@typed-hole.org>
date: Fri Apr 7 08:49:33 EDT 2023

Formatting

--- a/.clang-format
+++ b/.clang-format
@@ -4,7 +4,7 @@
 UseTab: Always
 AllowShortFunctionsOnASingleLine: InlineOnly
 AlwaysBreakAfterReturnType: TopLevelDefinitions
-BreakBeforeBraces: Allman
+BreakBeforeBraces: WebKit
 SpaceBeforeParens: false
 PointerAlignment: Right
 AlignTrailingComments: true
--- a/http.c
+++ b/http.c
@@ -14,11 +14,11 @@
 	int n, fd;
 
 	if((fd = open("/mnt/web/clone", ORDWR)) < 0)
-		sysfatal("couldn't open %s: %r", buf);
+		sysfatal("webclone: couldn't open %s: %r", buf);
 	if((n = read(fd, buf, sizeof buf - 1)) < 0)
-		sysfatal("reading clone: %r");
+		sysfatal("webclone: reading clone: %r");
 	if(n == 0)
-		sysfatal("short read on clone");
+		sysfatal("webclone: short read on clone");
 	buf[n] = '\0';
 	*c = atoi(buf);
 
@@ -37,20 +37,20 @@
 
 	snprint(buf, sizeof buf, "url %s", url);
 	if(write(ctlfd, buf, n = strlen(buf)) != n)
-		sysfatal("post: write: %r");
+		sysfatal("httpget: write url: %r");
 
 	/* Request */
-	bearer_token = concat("Authorization: Bearer ", token);
+	bearer_token = esmprint("Authorization: Bearer %s", token);
 	if(fprint(ctlfd, "headers %s", bearer_token) <= 0)
-		sysfatal("write ctl failed 'headers'");
+		sysfatal("httpget: write headers: %r");
 
 	snprint(buf, sizeof(buf), "/mnt/web/%d/body", conn);
 
 	/* Response */
 	if((bodyfd = open(buf, OREAD)) < 0)
-		sysfatal("open %s: %r", buf);
+		sysfatal("httpget: open %s: %r", buf);
 	if(readn(bodyfd, body, TLBUFSIZE) <= 0)
-		sysfatal("readn: %r");
+		sysfatal("httpget: readn: %r");
 
 	close(bodyfd);
 	close(ctlfd);
@@ -69,20 +69,18 @@
 
 	snprint(buf, sizeof buf, "url %s", url);
 	if(write(ctlfd, buf, n = strlen(buf)) != n)
-		sysfatal("post: write: %r");
+		sysfatal("httppost: write url: %r");
 
 	/* Request */
-	bearer_token = concat("Authorization: Bearer ", token);
+	bearer_token = esmprint("Authorization: Bearer %s", token);
 	if(fprint(ctlfd, "headers %s", bearer_token) <= 0)
-		sysfatal("write ctl failed 'headers'");
+		sysfatal("httppost: write headers: %r");
 
 	snprint(buf, TOOTBUFSIZE, "/mnt/web/%d/postbody", conn);
-	bodyfd = open(buf, OWRITE);
-	if(bodyfd < 0)
-		sysfatal("open bodyfd %s: %r", buf);
-
+	if((bodyfd = open(buf, OWRITE)) < 0)
+		sysfatal("httppost: open %s: %r", buf);
 	if(write(bodyfd, text, strlen(text)) < 0)
-		sysfatal("write: %r");
+		sysfatal("httppost: write: %r");
 
 	close(bodyfd);
 
@@ -89,9 +87,9 @@
 	/* Response */
 	snprint(buf, TOOTBUFSIZE, "/mnt/web/%d/body", conn);
 	if((bodyfd = open(buf, OREAD)) < 0)
-		sysfatal("post: opening body: %r");
+		sysfatal("httppost: open %s: %r", buf);
 	if(readn(bodyfd, buf, TOOTBUFSIZE) <= 0)
-		sysfatal("readn: %r");
+		sysfatal("httppost: readn: %r");
 
 	close(bodyfd);
 	close(ctlfd);
@@ -128,12 +126,10 @@
 	char *bearer_token, *multipart_header;
 	FileAttachment *fa;
 
-	ctlfd = open("/mnt/web/clone", ORDWR);
-	if(ctlfd < 0)
-		sysfatal("open: %r");
-	n = read(ctlfd, buf, sizeof(buf));
-	if(n < 0)
-		sysfatal("read: %r");
+	if((ctlfd = open("/mnt/web/clone", ORDWR)) < 0)
+		sysfatal("upload: open: %r");
+	if((n = read(ctlfd, buf, sizeof(buf))) < 0)
+		sysfatal("upload: read: %r");
 	buf[n] = '\0';
 	conn = atoi(buf);
 
@@ -141,19 +137,19 @@
 
 	snprint(buf, sizeof buf, "url %s", url);
 	if(write(ctlfd, buf, n = strlen(buf)) != n)
-		sysfatal("post: write: %r");
+		sysfatal("upload: write: %r");
 	bearer_token = esmprint("Authorization: Bearer %s", token);
 	snprint(buf, sizeof buf, "headers %s", bearer_token);
 	if(write(ctlfd, buf, n = strlen(buf)) != n)
-		sysfatal("post: write headers: %r");
+		sysfatal("upload: write headers: %r");
 	snprint(buf, sizeof buf, "contenttype multipart/form-data; boundary=%s",
 			BOUNDARY);
 	if(write(ctlfd, buf, n = strlen(buf)) != n)
-		sysfatal("post: write contenttype: %r");
+		sysfatal("upload: write contenttype: %r");
 
 	snprint(buf, sizeof buf, "/mnt/web/%d/postbody", conn);
 	if((bodyfd = open(buf, OWRITE)) < 0)
-		sysfatal("open bodyfd %s: %r", buf);
+		sysfatal("upload: open %s: %r", buf);
 
 	/* Write multipart body */
 	write(bodyfd, "--", 2);
@@ -178,9 +174,9 @@
 	/* Response */
 	snprint(buf, sizeof buf, "/mnt/web/%d/body", conn);
 	if((bodyfd = open(buf, OREAD)) < 0)
-		sysfatal("post: opening body: %r");
+		sysfatal("upload: open %s: %r", buf);
 	if(readn(bodyfd, buf, BUFSIZE) <= 0)
-		sysfatal("readn: %r");
+		sysfatal("upload: readn: %r");
 
 	close(bodyfd);
 	close(ctlfd);
--- a/masto9.c
+++ b/masto9.c
@@ -12,97 +12,85 @@
 {
 	UserPasswd *p;
 
-	p = auth_getuserpasswd(auth_getkey, "proto=pass service=mastodon server=%s",
-						   host);
-	if(p == nil)
-		sysfatal("masto9: failed to retrieve token: %r");
+	if((p = auth_getuserpasswd(
+			auth_getkey, "proto=pass service=mastodon server=%s", host)) == nil)
+		sysfatal("getcredentials: failed to retrieve token: %r");
 
 	return p;
 }
 
 void
-gethome(char *token, char *host, Toot toots[], char *after)
+gethome(char *token, char *host, Toot toots[], char *beforeid)
 {
-	JSON *obj, *id, *content, *reblog_content, *account, *reblog_account,
-		*handle, *reblog_handle, *display_name, *avatar, *reblog,
-		*media_attachments, *type, *preview_url, *remote_url;
+	JSON *obj, *id, *content, *reblogcontent, *account, *reblogaccount,
+		*handle, *rebloghandle, *displayname, *avatar, *reblog,
+		*mediaattachments, *type, *previewurl, *remoteurl;
 	char *endpoint;
 	int i = 0;
 
-	if(after != nil)
-	{
-		endpoint = esmprint("timelines/home?max_id=%s", after);
-	}
-	else
-	{
+	if(beforeid != nil) {
+		endpoint = esmprint("timelines/home?max_id=%s", beforeid);
+	} else {
 		endpoint = "timelines/home";
 	}
 
 	obj = mastodonget(token, host, endpoint);
 	if(obj->t != JSONArray)
-		sysfatal("jsonparse: not an array");
+		sysfatal("gethome: jsonparse: not an array");
 
-	for(JSONEl *p = obj->first; p != nil; p = p->next)
-	{
-		JSON *toot_json = p->val;
+	for(JSONEl *p = obj->first; p != nil; p = p->next) {
+		JSON *tootjson = p->val;
 
-		id = getjsonkey(toot_json, "id");
-		content = getjsonkey(toot_json, "content");
-		account = getjsonkey(toot_json, "account");
+		id = getjsonkey(tootjson, "id");
+		content = getjsonkey(tootjson, "content");
+		account = getjsonkey(tootjson, "account");
 		handle = getjsonkey(account, "acct");
-		display_name = getjsonkey(account, "display_name");
+		displayname = getjsonkey(account, "display_name");
 		avatar = getjsonkey(account, "avatar_static");
-		reblog = getjsonkey(toot_json, "reblog");
-		media_attachments = getjsonkey(toot_json, "media_attachments");
+		reblog = getjsonkey(tootjson, "reblog");
+		mediaattachments = getjsonkey(tootjson, "media_attachments");
 
 		Toot *toot = emalloc(sizeof(Toot));
 		toot->id = estrdup((char *)id->s);
 
-		if(reblog->s == nil)
-		{
+		if(reblog->s == nil) {
 			toot->reblogged = 0;
 			toot->content = estrdup((char *)content->s);
-		}
-		else
-		{
-			reblog_content = getjsonkey(reblog, "content");
-			reblog_account = getjsonkey(reblog, "account");
-			reblog_handle = getjsonkey(reblog_account, "acct");
+		} else {
+			reblogcontent = getjsonkey(reblog, "content");
+			reblogaccount = getjsonkey(reblog, "account");
+			rebloghandle = getjsonkey(reblogaccount, "acct");
 
-			toot->content = estrdup((char *)reblog_content->s);
-			toot->reblogged_handle = estrdup((char *)reblog_handle->s);
+			toot->content = estrdup((char *)reblogcontent->s);
+			toot->rebloggedhandle = estrdup((char *)rebloghandle->s);
 			toot->reblogged = 1;
 
-			media_attachments = getjsonkey(reblog, "media_attachments");
+			mediaattachments = getjsonkey(reblog, "media_attachments");
 		};
 		toot->handle = estrdup((char *)handle->s);
-		toot->display_name = estrdup((char *)display_name->s);
-		toot->avatar_url = estrdup((char *)avatar->s);
-		toot->attachments_count = 0;
+		toot->displayname = estrdup((char *)displayname->s);
+		toot->avatarurl = estrdup((char *)avatar->s);
+		toot->attachmentscount = 0;
 
-		if(media_attachments->s != nil)
-		{
+		if(mediaattachments->s != nil) {
 			int j = 0;
-			for(JSONEl *at = media_attachments->first; at != nil; at = at->next)
-			{
-				JSON *attachment_json = at->val;
+			for(JSONEl *at = mediaattachments->first; at != nil;
+				at = at->next) {
+				JSON *attachmentjson = at->val;
 				Attachment *attachment = emalloc(sizeof(Attachment));
-				type = getjsonkey(attachment_json, "type");
-				preview_url = getjsonkey(attachment_json, "preview_url");
-				remote_url = getjsonkey(attachment_json, "remote_url");
+				type = getjsonkey(attachmentjson, "type");
+				previewurl = getjsonkey(attachmentjson, "preview_url");
+				remoteurl = getjsonkey(attachmentjson, "remote_url");
 				attachment->type = estrdup((char *)type->s);
 
-				if(strcmp(type->s, "image") == 0)
-				{
-					attachment->url = estrdup((char *)preview_url->s);
+				if(strcmp(type->s, "image") == 0) {
+					attachment->url = estrdup((char *)previewurl->s);
+				} else {
+					attachment->url = estrdup((char *)remoteurl->s);
 				}
-				else
-				{
-					attachment->url = estrdup((char *)remote_url->s);
-				}
 
-				toot->media_attachments[j] = attachment;
-				toot->attachments_count++;
+				toot->mediaattachments[j] = attachment;
+				toot->attachmentscount++;
 				j++;
 			}
 		}
@@ -113,33 +101,35 @@
 }
 
 void
-getnotifications(char *token, char *host, Notification *notifs)
+getnotifications(char *token, char *host, Notification *notifs, char *filter)
 {
-	JSON *obj, *id, *content, *display_name, *handle, *type, *account, *status;
+	JSON *obj, *id, *content, *displayname, *handle, *type, *account, *status;
+	char *endpoint;
 	int i = 0;
 
-	obj = mastodonget(token, host, "notifications?types[]=mention");
+	if(strlen(filter) > 0) {
+		endpoint = esmprint("notifications?types[]=%s", filter);
+	} else {
+		endpoint = "notifications";
+	}
+	obj = mastodonget(token, host, endpoint);
 
 	if(obj->t != JSONArray)
-		sysfatal("jsonparse: not an array");
+		sysfatal("getnotifications: jsonparse: not an array");
 
-	for(JSONEl *p = obj->first; p != nil; p = p->next)
-	{
-		JSON *notif_json = p->val;
+	for(JSONEl *p = obj->first; p != nil; p = p->next) {
+		JSON *notifjson = p->val;
 
-		id = getjsonkey(notif_json, "id");
-		type = getjsonkey(notif_json, "type");
-		if(strcmp(type->s, "follow") != 0)
-		{
-			status = getjsonkey(notif_json, "status");
+		id = getjsonkey(notifjson, "id");
+		type = getjsonkey(notifjson, "type");
+		if(strcmp(type->s, "follow") != 0) {
+			status = getjsonkey(notifjson, "status");
 			content = getjsonkey(status, "content");
-		}
-		else
-		{
+		} else {
 			content = jsonparse("");
 		}
-		account = getjsonkey(notif_json, "account");
-		display_name = getjsonkey(account, "display_name");
+		account = getjsonkey(notifjson, "account");
+		displayname = getjsonkey(account, "display_name");
 		handle = getjsonkey(account, "acct");
 
 		Notification *notif = emalloc(sizeof(Notification));
@@ -146,11 +136,10 @@
 		notif->id = estrdup((char *)id->s);
 
 		notif->type = estrdup((char *)type->s);
-		if(strcmp(type->s, "follow") != 0)
-		{
+		if(strcmp(type->s, "follow") != 0) {
 			notif->content = estrdup((char *)content->s);
 		}
-		notif->display_name = estrdup((char *)display_name->s);
+		notif->displayname = estrdup((char *)displayname->s);
 		notif->handle = estrdup((char *)handle->s);
 
 		notifs[i] = *notif;
@@ -165,7 +154,7 @@
 	char *url;
 	url = esmprint("https://%s/api/v1/statuses", host);
 
-	httppost(token, url, concat("status=", text));
+	httppost(token, url, esmprint("status=%s", text));
 	print("Posted:\n %s\n", text);
 }
 
@@ -175,16 +164,13 @@
 	JSON *obj, *account, *reblog;
 	char *endpoint, *response;
 
-	endpoint = concat("statuses/", id);
+	endpoint = esmprint("statuses/%s", id);
 	obj = mastodonget(token, host, endpoint);
 
 	reblog = getjsonkey(obj, "reblog");
-	if(reblog->s != nil)
-	{
+	if(reblog->s != nil) {
 		account = getjsonkey(reblog, "account");
-	}
-	else
-	{
+	} else {
 		account = getjsonkey(obj, "account");
 	}
 
@@ -206,21 +192,16 @@
 	url = esmprint("https://%s/api/v1/media", host);
 	response = upload(token, url, filepath);
 
-	obj = jsonparse(response);
-	if(obj == nil)
-		sysfatal("jsonparse: not json");
+	if((obj = jsonparse(response)) == nil)
+		sysfatal("postattachment: jsonparse: not json");
 
-	print("%J\n", obj);
 	id = getjsonkey(obj, "id");
 
 	url = esmprint("https://%s/api/v1/statuses", host);
 
-	if(strlen(text) > 0)
-	{
+	if(strlen(text) > 0) {
 		body = esmprint("status=%s&media_ids[]=%s", text, id->s);
-	}
-	else
-	{
+	} else {
 		body = esmprint("media_ids[]=%s", id->s);
 	}
 	httppost(token, url, body);
@@ -231,7 +212,7 @@
 perform(char *token, char *host, char *id, char *action)
 {
 	char *url;
-	url = esmprint("%s/api/v1/statuses/%s/%s", host, id, action);
+	url = esmprint("https://%s/api/v1/statuses/%s/%s", host, id, action);
 	httppost(token, url, "");
 }
 
@@ -276,8 +257,7 @@
 
 	if(wait)
 		close(open("/dev/text", OWRITE | OTRUNC | OCEXEC));
-	if((fd = open("/dev/consctl", OWRITE | OCEXEC)) >= 0)
-	{
+	if((fd = open("/dev/consctl", OWRITE | OCEXEC)) >= 0) {
 		write(fd, "holdon", 6);
 		u = tootauthor(token, host, id);
 		print("Reply to %s\n", u);
@@ -285,8 +265,7 @@
 		if((s = Brdstr(&body, 0, 1)) != nil)
 			t = esmprint("%s", s);
 		free(s);
-		if(t != nil)
-		{
+		if(t != nil) {
 			url = esmprint("%s/api/v1/statuses", host);
 			content = esmprint("in_reply_to_id=%s&status=@%s %s", id, u, t);
 
@@ -293,15 +272,11 @@
 			httppost(token, url, content);
 			print("\nReply sent.\n");
 			free(t);
-		}
-		else
-		{
+		} else {
 			fprint(2, "%r\n");
 		}
 		close(fd);
-	}
-	else
-	{
+	} else {
 		fprint(2, "%r\n");
 	}
 }
@@ -313,11 +288,10 @@
 	char buf[TOOTBUFSIZE];
 
 	if(pipe(wr) == -1 || pipe(rd) == -1)
-		sysfatal("pipe: %r");
-	switch(fork())
-	{
+		sysfatal("fmthtml: pipe: %r");
+	switch(fork()) {
 	case -1:
-		sysfatal("fork: %r");
+		sysfatal("fmthtml: fork: %r");
 		break;
 	case 0:
 		close(wr[0]);
@@ -325,7 +299,7 @@
 		dup(wr[1], 0);
 		dup(rd[0], 1);
 		execl("/bin/htmlfmt", "htmlfmt -cutf-8 -j", nil);
-		sysfatal("exec: %r");
+		sysfatal("fmthtml: exec: %r");
 		break;
 	default:
 		close(wr[1]);
@@ -335,7 +309,7 @@
 		n = readn(rd[1], buf, sizeof(buf));
 		close(rd[1]);
 		if(n == -1)
-			sysfatal("read: %r\n");
+			sysfatal("fmthtml: read: %r\n");
 		buf[n] = 0;
 		return buf;
 	}
@@ -360,9 +334,8 @@
 	url = esmprint("https://%s/api/v1/%s", host, endpoint);
 	response = httpget(token, url);
 
-	obj = jsonparse(response);
-	if(obj == nil)
-		sysfatal("jsonparse: not json");
+	if((obj = jsonparse(response)) == nil)
+		sysfatal("mastodonget: jsonparse: not json");
 
 	return (obj);
 }
@@ -379,29 +352,23 @@
 	Biobuf out;
 	Binit(&out, 1, OWRITE);
 
-	for(int i = 0; i < TOOTSCOUNT; i++)
-	{
+	for(int i = 0; i < TOOTSCOUNT; i++) {
 		Toot toot = toots[i];
 		char *username;
 
-		username = esmprint("%s (%s)", toot.display_name, toot.handle);
+		username = esmprint("%s (%s)", toot.displayname, toot.handle);
 
 		Bprint(&out, "\n\n——————————\n");
-		if(toot.reblogged == 1)
-		{
+		if(toot.reblogged == 1) {
 			Bprint(&out, "⊙ %s retooted %s:\n", username,
-				   toot.reblogged_handle);
-		}
-		else
-		{
+				   toot.rebloggedhandle);
+		} else {
 			Bprint(&out, "⊙ %s:\n", username);
 		}
 		Bprint(&out, "\n%s", fmthtml(cleanup(toot.content)));
-		if(toot.attachments_count > 0)
-		{
-			for(int j = 0; j < toot.attachments_count; j++)
-			{
-				Attachment *attachment = toot.media_attachments[j];
+		if(toot.attachmentscount > 0) {
+			for(int j = 0; j < toot.attachmentscount; j++) {
+				Attachment *attachment = toot.mediaattachments[j];
 				Bprint(&out, "\n[%s] %s", attachment->type, attachment->url);
 			}
 			Bprint(&out, "\n");
@@ -420,34 +387,24 @@
 	Biobuf out;
 	Binit(&out, 1, OWRITE);
 
-	for(int i = 0; i < NOTIFSCOUNT; i++)
-	{
+	for(int i = 0; i < NOTIFSCOUNT; i++) {
 		Notification notif = notifs[i];
 		char *username;
 
-		username = esmprint("%s (%s)", notif.display_name, notif.handle);
+		username = esmprint("%s (%s)", notif.displayname, notif.handle);
 
-		if(strcmp(notif.type, "reblog") == 0)
-		{
+		if(strcmp(notif.type, "reblog") == 0) {
 			Bprint(&out, "\n⊙ %s retooted\n %s", username,
 				   fmthtml(cleanup(notif.content)));
-		}
-		else if(strcmp(notif.type, "favourite") == 0)
-		{
+		} else if(strcmp(notif.type, "favourite") == 0) {
 			Bprint(&out, "\n⊙ %s favorited\n %s", username,
 				   fmthtml(cleanup(notif.content)));
-		}
-		else if(strcmp(notif.type, "mention") == 0)
-		{
+		} else if(strcmp(notif.type, "mention") == 0) {
 			Bprint(&out, "\n⊙ %s mentioned you\n %s", username,
 				   fmthtml(cleanup(notif.content)));
-		}
-		else if(strcmp(notif.type, "follow") == 0)
-		{
+		} else if(strcmp(notif.type, "follow") == 0) {
 			Bprint(&out, "\n⊙ %s followed you\n", username);
-		}
-		else if(strcmp(notif.type, "poll") == 0)
-		{
+		} else if(strcmp(notif.type, "poll") == 0) {
 			Bprint(&out, "\n⊙ %s poll ended\n %s", username,
 				   fmthtml(cleanup(notif.content)));
 		}
@@ -468,8 +425,6 @@
 	jsonfree(obj);
 }
 
-// echo 'proto=pass service=mastodon server=instanceHostName pass=yourToken
-// user=yourUsername' > /mnt/factotum/ctl
 void
 main(int argc, char **argv)
 {
@@ -487,72 +442,52 @@
 	p = getcredentials(host);
 	token = p->passwd;
 
-	if(command == nil)
-	{
+	if(command == nil) {
 		Toot toots[TOOTSCOUNT];
 		gethome(token, host, toots, nil);
 		displaytoots(toots, host);
-	}
-	else if(strcmp(command, "toot") == 0)
-	{
+	} else if(strcmp(command, "toot") == 0) {
 		text = argv[3];
 		posttoot(token, host, text);
-	}
-	else if(strcmp(command, "tootfile") == 0)
-	{
-		if(argc > 4)
-		{
+	} else if(strcmp(command, "tootfile") == 0) {
+		if(argc > 4) {
 			text = argv[3];
 			filepath = argv[4];
-		}
-		else
-		{
+		} else {
 			text = "";
 			filepath = argv[3];
 		}
 		postattachment(token, host, text, filepath);
-	}
-	else if(strcmp(command, "fav") == 0)
-	{
+	} else if(strcmp(command, "fav") == 0) {
 		id = argv[3];
 		fav(token, host, id);
-	}
-	else if(strcmp(command, "unfav") == 0)
-	{
+	} else if(strcmp(command, "unfav") == 0) {
 		id = argv[3];
 		unfav(token, host, id);
-	}
-	else if(strcmp(command, "boost") == 0)
-	{
+	} else if(strcmp(command, "boost") == 0) {
 		id = argv[3];
 		boost(token, host, id);
-	}
-	else if(strcmp(command, "unboost") == 0)
-	{
+	} else if(strcmp(command, "unboost") == 0) {
 		id = argv[3];
 		unboost(token, host, id);
-	}
-	else if(strcmp(command, "reply") == 0)
-	{
+	} else if(strcmp(command, "reply") == 0) {
 		id = argv[3];
 		reply(token, host, id);
-	}
-	else if(strcmp(command, "debug") == 0)
-	{
+	} else if(strcmp(command, "debug") == 0) {
 		id = argv[3];
 		debug(token, host, id);
-	}
-	else if(strcmp(command, "more") == 0)
-	{
+	} else if(strcmp(command, "more") == 0) {
 		id = argv[3];
 		Toot toots[TOOTSCOUNT];
 		gethome(token, host, toots, id);
 		displaytoots(toots, host);
-	}
-	else if(strcmp(command, "notifications") == 0)
-	{
+	} else if(strcmp(command, "notifications") == 0) {
 		Notification notifs[NOTIFSCOUNT];
-		getnotifications(token, host, notifs);
+		getnotifications(token, host, notifs, "");
+		displaynotifications(notifs);
+	} else if(strcmp(command, "mentions") == 0) {
+		Notification notifs[NOTIFSCOUNT];
+		getnotifications(token, host, notifs, "mention");
 		displaynotifications(notifs);
 	}
 
--- a/masto9.h
+++ b/masto9.h
@@ -12,7 +12,7 @@
   char *id;
   char *type;
   char *handle;
-  char *display_name;
+  char *displayname;
   char *content;
 } Notification;
 
@@ -20,13 +20,13 @@
 	char *id;
 	char *content;
 	char *handle;
-	char *display_name;
-	char *avatar_url;
-	char *in_reply_to_account_id;
+	char *displayname;
+	char *avatarurl;
+	char *inreplytoaccountid;
 	int reblogged;
-	char *reblogged_handle;
-	Attachment *media_attachments[10];
-	int attachments_count;
+	char *rebloggedhandle;
+	Attachment *mediaattachments[10];
+	int attachmentscount;
 } Toot;
 
 enum {
@@ -47,13 +47,11 @@
 char *upload(char *token, char *url, char *filename);
 
 /* utils */
-char *concat(char *s1, char *s2);
 void *emalloc(ulong);
 char *estrdup(char*);
 char *estrjoin(char **strings, char *sep);
 char *esmprint(char*, ...);
 char *fslurp(int, int*);
-u32int strhash(char *);
 void removesubstring(char *, char *);
 void removetag(char *, char *);
 JSON *getjsonkey(JSON *, char *);
--- a/util.c
+++ b/util.c
@@ -12,8 +12,7 @@
 {
 	void *v;
 
-	v = mallocz(n, 1);
-	if(v == nil)
+	if((v = mallocz(n, 1)) == nil)
 		sysfatal("malloc: %r");
 	setmalloctag(v, getcallerpc(&n));
 	return v;
@@ -24,8 +23,7 @@
 {
 	void *v;
 
-	v = realloc(p, n);
-	if(v == nil)
+	if((v = realloc(p, n)) == nil)
 		sysfatal("realloc: %r");
 	setmalloctag(v, getcallerpc(&p));
 	return v;
@@ -34,8 +32,7 @@
 char *
 estrdup(char *s)
 {
-	s = strdup(s);
-	if(s == nil)
+	if((s = strdup(s)) == nil)
 		sysfatal("strdup: %r");
 	setmalloctag(s, getcallerpc(&s));
 	return s;
@@ -42,20 +39,6 @@
 }
 
 char *
-concat(char *s1, char *s2)
-{
-	int len1 = strlen(s1);
-	int len2 = strlen(s2);
-	char *result;
-
-	result =
-		emalloc(sizeof(char) * (len1 + len2 + 1)); // +1 for the null-terminator
-	memcpy(result, s1, len1);
-	memcpy(result + len1, s2, len2 + 1);
-	return result;
-}
-
-char *
 esmprint(char *fmt, ...)
 {
 	char *s;
@@ -79,8 +62,7 @@
 	n = 0;
 	sz = 128;
 	buf = emalloc(sz);
-	while(1)
-	{
+	while(1) {
 		r = read(fd, buf + n, sz - n);
 		if(r == 0)
 			break;
@@ -87,8 +69,7 @@
 		if(r == -1)
 			goto error;
 		n += r;
-		if(n == sz)
-		{
+		if(n == sz) {
 			sz += sz / 2;
 			buf = erealloc(buf, sz);
 		}
@@ -107,8 +88,7 @@
 {
 	int len = strlen(sub);
 
-	while((str = strstr(str, sub)))
-	{
+	while((str = strstr(str, sub))) {
 		memmove(str, str + len, strlen(str + len) + 1);
 	}
 }
@@ -118,16 +98,12 @@
 {
 	char *start = strstr(str, tag);
 
-	while(start)
-	{
+	while(start) {
 		char *end = strchr(start, '>');
 
-		if(end)
-		{
+		if(end) {
 			memmove(start, end + 1, strlen(end + 1) + 1);
-		}
-		else
-		{
+		} else {
 			*start = '\0';
 			break;
 		}
@@ -139,9 +115,9 @@
 JSON *
 getjsonkey(JSON *obj, char *key)
 {
-	JSON *value = jsonbyname(obj, key);
-	if(value == nil)
-		sysfatal("jsonbyname: key %s not found in %J", key, obj);
+	JSON *value;
+	if((value = jsonbyname(obj, key)) == nil)
+		sysfatal("getjsonkey: jsonbyname: key %s not found in %J", key, obj);
 	return value;
 }
 
@@ -150,29 +126,24 @@
 {
 	int fd, nread, size = 0, bufsize = 1024;
 	FileAttachment *fa = emalloc(sizeof(FileAttachment));
-	char *buf = malloc(bufsize);
-	if(!buf)
-		sysfatal("malloc failed");
+	char *buf = emalloc(bufsize);
 
-	fd = open(filename, OREAD);
-	if(fd < 0)
-		sysfatal("open %s: %r", filename);
+	if((fd = open(filename, OREAD)) < 0)
+		sysfatal("readfile: open %s: %r", filename);
 
-	while((nread = read(fd, buf + size, bufsize - size)) > 0)
-	{
+	while((nread = read(fd, buf + size, bufsize - size)) > 0) {
 		size += nread;
-		if(size == bufsize)
-		{
+		if(size == bufsize) {
 			bufsize *= 2;
 			buf = realloc(buf, bufsize);
 			if(!buf)
-				sysfatal("realloc failed");
+				sysfatal("readfile: realloc failed");
 		}
 	}
 	close(fd);
 
 	if(nread < 0)
-		sysfatal("read %s: %r", filename);
+		sysfatal("readfile: read %s: %r", filename);
 
 	buf[size] = '\0';