shithub: masto9

Download patch

ref: 416e913d695eea696560b129c98cd3038efa103a
parent: 49ba85bf6b67c33707cd56111d9868e610c429ae
author: Julien Blanchard <jblanchard@makemusic.com>
date: Sun Mar 26 11:51:23 EDT 2023

Split files, add boost and fav

--- /dev/null
+++ b/http.c
@@ -1,0 +1,108 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+
+#include "masto9.h"
+
+char *
+httpget(char *token, char *url)
+{
+	int	ctlfd, bodyfd, conn, n;
+	char buf[1024];
+	char *body;
+  char *bearer_token;
+
+	ctlfd = open("/mnt/web/clone", ORDWR);
+	if (ctlfd < 0)
+		sysfatal("open: %r");
+	n = read(ctlfd, buf, sizeof(buf));
+	if (n < 0)
+		sysfatal("read: %r");
+	buf[n] = 0;
+	conn = atoi(buf);
+
+	/* the write(2) syscall (used by fprint) is considered
+	 * failed if it returns -1 or N != Nwritten. to check for
+	 * error here you'd have to snprint the url to a temporary
+	 * buffer, get its length, then write it out and check the
+	 * amount written against the length */
+	if (fprint(ctlfd, "url %s", url) <= 0)
+		sysfatal("write ctl failed 'url %s': %r", url);
+
+  bearer_token = concat("Authorization: Bearer ", token);
+
+	if (fprint(ctlfd, "headers %s", bearer_token) <= 0)
+		sysfatal("write ctl failed 'headers'");
+
+	snprint(buf, sizeof(buf), "/mnt/web/%d/body", conn);
+
+	bodyfd = open(buf, OREAD);
+	if (bodyfd < 0)
+		sysfatal("open %s: %r", buf);
+
+  body = emalloc(TLBUFSIZE * sizeof(char));
+	if (readn(bodyfd, body, TLBUFSIZE) <= 0)
+		sysfatal("readn: %r");
+
+	close(bodyfd);
+	close(ctlfd);
+  print("BODY %d", strlen(body));
+  return body;
+}
+
+char *
+httppost(char *token, char *url, char *text)
+{
+	int	ctlfd, bodyfd, conn, n;
+	char *buf;
+  char *bearer_token;
+
+  buf = emalloc(TOOTBUFSIZE * sizeof(char));
+
+	ctlfd = open("/mnt/web/clone", ORDWR);
+	if (ctlfd < 0)
+		sysfatal("open ctlfd: %r");
+	/* n = write(ctlfd, Contenttype, sizeof(Contenttype)); */
+	/* if (n < 0) */
+	/* 	sysfatal("write: %r"); */
+	/* buf[n] = 0; */
+	conn = atoi(buf);
+
+	/* the write(2) syscall (used by fprint) is considered
+	 * failed if it returns -1 or N != Nwritten. to check for
+	 * error here you'd have to snprint the url to a temporary
+	 * buffer, get its length, then write it out and check the
+	 * amount written against the length */
+	if (fprint(ctlfd, "url %s", url) <= 0)
+		sysfatal("write ctl failed 'url %s': %r", url);
+
+  bearer_token = concat("Authorization: Bearer ", token);
+
+	if (fprint(ctlfd, "headers %s", bearer_token) <= 0)
+		sysfatal("write ctl failed 'headers'");
+
+	snprint(buf, TOOTBUFSIZE, "/mnt/web/%d/postbody", conn);
+	bodyfd = open(buf, OWRITE);
+	if (bodyfd < 0)
+		sysfatal("open bodyfd %s: %r", buf);
+
+  if (write(bodyfd, text, strlen(text)) < 0)
+    sysfatal("write: %r");
+
+	close(bodyfd);
+	snprint(buf, TOOTBUFSIZE, "/mnt/web/%d/body", conn);
+
+  bodyfd = open(buf, OREAD);
+	if (bodyfd < 0)
+		sysfatal("open %s: %r", buf);
+
+	if (readn(bodyfd, buf, TOOTBUFSIZE) <= 0)
+		sysfatal("readn: %r");
+
+  /* print("BUF %s", buf); */
+
+	close(bodyfd);
+	close(ctlfd);
+
+  return buf;
+}
--- a/masto9.c
+++ b/masto9.c
@@ -4,47 +4,12 @@
 #include <json.h>
 #include <auth.h>
 
-#define Contenttype	"contenttype application/json"
+#include "masto9.h"
 
-typedef struct Attachment {
-	char *type;
-	char *url;
-} Attachment;
-
-typedef struct Notification {
-  char *id;
-  char *type;
-  char *username;
-  char *content;
-} Notification;
-
-typedef struct Toot {
-	char *id;
-	char *content;
-	char *username;
-	char *display_name;
-	char *avatar_url;
-	char *in_reply_to_account_id;
-	int reblogged;
-	char *reblogged_username;
-	Attachment media_attachments[10];
-	int attachments_count;
-} Toot;
-
-enum {
-	BUFSIZE = 8182,
-	MAX_URL = 1024,
-	TOOTS_COUNT = 20,
-	NOTIFS_COUNT = 15
-};
-
 char *URL = "https://fedi.9til.de/api/v1/timelines/home";
 char *POSTURL = "https://fedi.9til.de/api/v1/statuses";
 char *NOTIFICATIONSURL = "https://fedi.9til.de/api/v1/notifications";
 
-Toot toots[TOOTS_COUNT];
-Notification notifs[TOOTS_COUNT];
-
 UserPasswd *
 getcredentials(char *host)
 {
@@ -58,115 +23,7 @@
 	return p;
 }
 
-char *
-concat(char *s1, char *s2)
-{
-  char *result;
-  result = malloc(strlen(s1) + strlen(s2) + 1); // +1 for the null-terminator
-	if (result == nil)
-		sysfatal("malloc: %r");
 
-  strcpy(result, s1);
-  strcat(result, s2);
-  return result;
-}
-
-static void
-httpget(char *token, char *url, char *body, int bufsize)
-{
-	int	ctlfd, bodyfd, conn, n;
-	char buf[1024];
-  char *bearer_token;
-
-	ctlfd = open("/mnt/web/clone", ORDWR);
-	if (ctlfd < 0)
-		sysfatal("open: %r");
-	n = read(ctlfd, buf, sizeof(buf));
-	if (n < 0)
-		sysfatal("read: %r");
-	buf[n] = 0;
-	conn = atoi(buf);
-
-	/* the write(2) syscall (used by fprint) is considered
-	 * failed if it returns -1 or N != Nwritten. to check for
-	 * error here you'd have to snprint the url to a temporary
-	 * buffer, get its length, then write it out and check the
-	 * amount written against the length */
-	if (fprint(ctlfd, "url %s", url) <= 0)
-		sysfatal("write ctl failed 'url %s': %r", url);
-
-  bearer_token = concat("Authorization: Bearer ", token);
-
-	if (fprint(ctlfd, "headers %s", bearer_token) <= 0)
-		sysfatal("write ctl failed 'headers'");
-
-	snprint(buf, sizeof(buf), "/mnt/web/%d/body", conn);
-
-	bodyfd = open(buf, OREAD);
-	if (bodyfd < 0)
-		sysfatal("open %s: %r", buf);
-
-	if (readn(bodyfd, body, bufsize) <= 0)
-		sysfatal("readn: %r");
-
-	close(bodyfd);
-	close(ctlfd);
-}
-
-static void
-httppost(char *token, char *url, char *response, int bufsize, char *text)
-{
-	int	ctlfd, bodyfd, conn, n;
-	char buf[1024];
-  char *bearer_token;
-
-	ctlfd = open("/mnt/web/clone", ORDWR);
-	if (ctlfd < 0)
-		sysfatal("open: %r");
-	/* n = write(ctlfd, Contenttype, sizeof(Contenttype)); */
-	/* if (n < 0) */
-	/* 	sysfatal("write: %r"); */
-	buf[n] = 0;
-	conn = atoi(buf);
-
-
-	/* the write(2) syscall (used by fprint) is considered
-	 * failed if it returns -1 or N != Nwritten. to check for
-	 * error here you'd have to snprint the url to a temporary
-	 * buffer, get its length, then write it out and check the
-	 * amount written against the length */
-	if (fprint(ctlfd, "url %s", url) <= 0)
-		sysfatal("write ctl failed 'url %s': %r", url);
-
-  bearer_token = concat("Authorization: Bearer ", token);
-
-	if (fprint(ctlfd, "headers %s", bearer_token) <= 0)
-		sysfatal("write ctl failed 'headers'");
-
-	snprint(buf, sizeof(buf), "/mnt/web/%d/postbody", conn);
-	bodyfd = open(buf, OWRITE);
-	if (bodyfd < 0)
-		sysfatal("open %s: %r", buf);
-
-  if (write(bodyfd, text, strlen(text)) < 0)
-    sysfatal("write: %r");
-
-	close(bodyfd);
-	snprint(buf, sizeof(buf), "/mnt/web/%d/body", conn);
-
-  bodyfd = open(buf, OREAD);
-	if (bodyfd < 0)
-		sysfatal("open %s: %r", buf);
-
-	if (readn(bodyfd, buf, sizeof(buf)) <= 0)
-		sysfatal("readn: %r");
-
-  /* print("BUF %s", buf); */
-
-	close(bodyfd);
-	close(ctlfd);
-}
-
 static JSON *
 get_json_key(JSON *obj, char *key)
 {
@@ -180,14 +37,12 @@
 get_timeline(char *token, Toot toots[])
 {
 	JSON *obj, *id, *content, *reblog_content, *account, *reblog_account, *username, *reblog_username, *display_name, *avatar, *reblog, *media_attachments, *type, *url;
-	char buf[BUFSIZE * 32];
+	char *response;
 	int i = 0;
 
-	httpget(token, URL, buf, sizeof(buf));
+	response = httpget(token, URL);
 
-	obj = jsonparse(buf);
-	//print("%J", obj);
-
+	obj = jsonparse(response);
 	if (obj == nil)
 		sysfatal("jsonparse: not json");
 	if (obj->t != JSONArray)
@@ -205,7 +60,7 @@
 		reblog = get_json_key(toot_json, "reblog");
 		media_attachments = get_json_key(toot_json, "media_attachments");
 
-		Toot toot = malloc(sizeof(Toot));
+		Toot toot = emalloc(sizeof(Toot));
 		toot.id = strdup((char *)id->s);
 
 		if(reblog->s == nil) {
@@ -233,7 +88,7 @@
 			for(JSONEl *at = media_attachments->first; at != nil; at = at->next) {
 				JSON *attachment_json = at->val;
 				//print("att: %J", attachment_json);
-				Attachment attachment = malloc(sizeof(Attachment));
+				Attachment attachment = emalloc(sizeof(Attachment));
 				type = get_json_key(attachment_json, "type");
 				url = get_json_key(attachment_json, "preview_url");
 				attachment.type = strdup((char *)type->s);
@@ -254,14 +109,12 @@
 get_notifications(char *token, Notification toots[])
 {
 	JSON *obj, *id, *content, *username, *type, *account, *status;
-	char buf[BUFSIZE * 32];
+	char *response;
 	int i = 0;
 
-	httpget(token, NOTIFICATIONSURL, buf, sizeof(buf));
+	response = httpget(token, NOTIFICATIONSURL);
 
-	obj = jsonparse(buf);
-	//print("%J", obj);
-
+  obj = jsonparse(response);
 	if (obj == nil)
 		sysfatal("jsonparse: not json");
 	if (obj->t != JSONArray)
@@ -269,6 +122,7 @@
 
 	for(JSONEl *p = obj->first; p != nil; p = p->next) {
 		JSON *toot_json = p->val;
+    content = emalloc(JSONNull);
 
 		id = get_json_key(toot_json, "id");
 		type = get_json_key(toot_json, "type");
@@ -279,7 +133,7 @@
     account = get_json_key(toot_json, "account");
     username = get_json_key(account, "username");
 
-		Notification toot = malloc(sizeof(Notification));
+		Notification toot = emalloc(sizeof(Notification));
 		toot.id = strdup((char *)id->s);
 
     toot.type = strdup((char *)type->s);
@@ -295,29 +149,59 @@
 void
 post_toot(char *token, char *text)
 {
-	char buf[BUFSIZE * 32];
-	httppost(token, POSTURL, buf, sizeof(buf), text);
+	char buf[TOOTBUFSIZE];
+	httppost(token, POSTURL, text);
   print("RESPONSE %s", buf);
 }
 
 void
+action_toot(char *token, char *id, char *action)
+{
+  char *response;
+  char url[1024];
+  snprintf(url, sizeof(url), "%s/%s/%s", POSTURL, id, action);
+  print("URL %s\n", url);
+  response = httppost(token, url, "");
+  print("Response:\n %s\n", response);
+}
+
+void
+boost_toot(char *token, char *id)
+{
+  action_toot(token, id, "reblog");
+}
+
+void
+unboost_toot(char *token, char *id)
+{
+  action_toot(token, id, "unreblog");
+}
+
+void
 fav_toot(char *token, char *id)
 {
-	char buf[BUFSIZE * 32];
-  char * url = concat(POSTURL, "/");
-  url = concat(url, id);
-  url = concat(url, "/favourite");
+  action_toot(token, id, "favourite");
+}
 
-  print("URL %s", url);
-	httppost(token, url, buf, sizeof(buf), "");
-  print("RESPONSE %s", buf);
+void
+unfav_toot(char *token, char *id)
+{
+  action_toot(token, id, "unfavourite");
 }
 
+void
+reply_toot(char *token, char *id, char *text)
+{
+  char content[TOOTBUFSIZE];
+  snprintf(content, TOOTBUFSIZE, "in_reply_to_id=%s&status=%s", id, text);
+	httppost(token, POSTURL, content);
+}
+
 char *
 fmthtml(char *msg)
 {
 	int wr[2], rd[2], n;
-	char buf[BUFSIZE];
+	char buf[TOOTBUFSIZE];
 
 	if(pipe(wr) == -1 || pipe(rd) == -1)
 		sysfatal("pipe: %r");
@@ -506,14 +390,12 @@
 mastodonget(char *token, char *host, char *endpoint)
 {
 	JSON *obj;
-	char buf[BUFSIZE], url[MAX_URL];
+	char *response, url[MAX_URL];
 
 	snprintf(url, MAX_URL, "https://%s/api/v1/%s", host, endpoint);
-	httpget(token, url, buf, sizeof(buf));
+	response = httpget(token, url);
 
-	obj = jsonparse(buf);
-	//print("%J", obj);
-
+	obj = jsonparse(response);
 	if (obj == nil)
 		sysfatal("jsonparse: not json");
 	if (obj->t != JSONArray)
@@ -571,9 +453,21 @@
   } else if(strcmp(command, "toot") == 0) {
     text = argv[3];
     post_toot(token, text);
-  } else if(strcmp(command, "favorite") == 0) {
+  } else if(strcmp(command, "fav") == 0) {
     id = argv[3];
     fav_toot(token, id);
+  } else if(strcmp(command, "unfav") == 0) {
+    id = argv[3];
+    unfav_toot(token, id);
+  } else if(strcmp(command, "boost") == 0) {
+    id = argv[3];
+    boost_toot(token, id);
+  } else if(strcmp(command, "unboost") == 0) {
+    id = argv[3];
+    unboost_toot(token, id);
+  } else if(strcmp(command, "reply") == 0) {
+    id = argv[3];
+    reply_toot(token, id, "@sirjofri@mastodon.sdf.org now this should be a proper reply");
   } else if(strcmp(command, "notifications") == 0) {
     get_notifications(token, notifs);
 
@@ -584,6 +478,8 @@
         print("⊙ %s retooted\n %s\n", notif.username, fmthtml(cleanup(notif.content)));
       } else if (strcmp(notif.type, "favourite") == 0) {
         print("⊙ %s favorited\n %s\n", notif.username, fmthtml(cleanup(notif.content)));
+      } else if (strcmp(notif.type, "mention") == 0) {
+        print("⊙ %s mentioned you\n %s\n", notif.username, fmthtml(cleanup(notif.content)));
       } else if (strcmp(notif.type, "follow") == 0) {
         print("⊙ %s followed you\n", notif.username);
       } else if (strcmp(notif.type, "poll") == 0) {
--- /dev/null
+++ b/masto9.h
@@ -1,0 +1,51 @@
+#define Contenttype	"contenttype application/json"
+
+typedef struct Attachment {
+	char *type;
+	char *url;
+} Attachment;
+
+typedef struct Notification {
+  char *id;
+  char *type;
+  char *username;
+  char *content;
+} Notification;
+
+typedef struct Toot {
+	char *id;
+	char *content;
+	char *username;
+	char *display_name;
+	char *avatar_url;
+	char *in_reply_to_account_id;
+	int reblogged;
+	char *reblogged_username;
+	Attachment media_attachments[10];
+	int attachments_count;
+} Toot;
+
+enum {
+	TOOTBUFSIZE = 8192,
+	TLBUFSIZE = 512000,
+	MAX_URL = 1024,
+	TOOTS_COUNT = 20,
+	NOTIFS_COUNT = 15
+};
+
+Toot toots[TOOTS_COUNT];
+Notification notifs[TOOTS_COUNT];
+
+/* http */
+char *httpget(char *token, char *url);
+char *httppost(char *token, char *url, char *text);
+
+/* utils */
+char *concat(char *s1, char *s2);
+void *emalloc(ulong);
+void *erealloc(void*, ulong);
+char *estrdup(char*);
+char *estrjoin(char **strings, char *sep);
+char *esmprint(char*, ...);
+char *fslurp(int, int*);
+u32int strhash(char*);
--- a/mkfile
+++ b/mkfile
@@ -5,7 +5,12 @@
 BIN=/$objtype/bin
 
 OFILES=\
+	http.$O\
 	masto9.$O\
+	util.$O\
+
+HFILES=masto9.h
+MAN=/sys/man/1/
 
 UPDATE=\
 	$HFILES\
--- /dev/null
+++ b/util.c
@@ -1,0 +1,131 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <thread.h>
+#include <regexp.h>
+
+#include "masto9.h"
+
+void *
+emalloc(ulong n)
+{
+	void *v;
+
+	v = mallocz(n, 1);
+	if(v == nil)
+		sysfatal("malloc: %r");
+	setmalloctag(v, getcallerpc(&n));
+	return v;
+}
+
+void *
+erealloc(void *p, ulong n)
+{
+	void *v;
+
+	v = realloc(p, n);
+	if(v == nil)
+		sysfatal("realloc: %r");
+	setmalloctag(v, getcallerpc(&p));
+	return v;
+}
+
+char*
+estrdup(char *s)
+{
+	s = strdup(s);
+	if(s == nil)
+		sysfatal("strdup: %r");
+	setmalloctag(s, getcallerpc(&s));
+	return s;
+}
+
+/* char* */
+/* estrjoin(char *s, ...) */
+/* { */
+/* 	va_list ap; */
+/* 	char *r, *t, *p, *e; */
+/* 	int n; */
+
+/* 	va_start(ap, s); */
+/* 	n = strlen(s) + 1; */
+/* 	while((p = va_arg(ap, char*)) != nil) */
+/* 		n += strlen(p); */
+/* 	va_end(ap); */
+
+/* 	r = emalloc(n); */
+/* 	e = r + n; */
+/* 	va_start(ap, s); */
+/* 	t = strecpy(r, e, s); */
+/* 	while((p = va_arg(ap, char*)) != nil) */
+/* 		t = strecpy(t, e, p); */
+/* 	va_end(ap); */
+/* 	return r; */
+/* } */
+
+char *
+concat(char *s1, char *s2)
+{
+  char *result;
+  result = emalloc(strlen(s1) + strlen(s2) + 1); // +1 for the null-terminator
+
+  strcpy(result, s1);
+  strcat(result, s2);
+  return result;
+}
+
+char*
+esmprint(char *fmt, ...)
+{
+	char *s;
+	va_list ap;
+
+	va_start(ap, fmt);
+	s = vsmprint(fmt, ap);
+	va_end(ap);
+	if(s == nil)
+		sysfatal("smprint: %r");
+	setmalloctag(s, getcallerpc(&fmt));
+	return s;
+}
+
+char*
+fslurp(int fd, int *nbuf)
+{
+	int n, sz, r;
+	char *buf;
+
+	n = 0;
+	sz = 128;
+	buf = emalloc(sz);
+	while(1){
+		r = read(fd, buf + n, sz - n);
+		if(r == 0)
+			break;
+		if(r == -1)
+			goto error;
+		n += r;
+		if(n == sz){
+			sz += sz/2;
+			buf = erealloc(buf, sz);
+		}
+	}
+	buf[n] = 0;
+	if(nbuf)
+		*nbuf = n;
+	return buf;
+error:
+	free(buf);
+	return nil;
+}
+
+u32int
+strhash(char *s)
+{
+	u32int h, c;
+
+	h = 5381;
+	while(c = *s++ & 0xff)
+		h = ((h << 5) + h) + c;
+	return h;
+}