/* full of jank */ #include #include #include #include #include #include #include #include #include #include #include #include "pdjson.h" #define MAX(x, y) ((x) > (y) ? (x) : (y)) #define MIN(x, y) ((x) < (y) ? (x) : (y)) #define USAGE "mvwtc id" #define HTTPOK "HTTP/1.1 200 OK" void url_hpn(stralloc *url, stralloc *host, stralloc *path, stralloc *name) { char *afterscheme; size_t urli, eohost, lastslash; urli = byte_chr(url->s, url->len, '/'); urli += 2; afterscheme = url->s + urli; eohost = byte_chr(url->s + urli, url->len - urli, '/'); stralloc_catb(host, url->s + urli, eohost); stralloc_0(host); stralloc_cats(path, url->s + urli + eohost); stralloc_0(host); lastslash = byte_rchr(url->s, url->len, '/'); stralloc_cats(name, url->s + lastslash + 1); stralloc_0(host); } /* '\n' → '\0' */ void sa_nltoz(stralloc *sa) { size_t idx; idx = byte_chr(sa->s, sa->len, '\n'); if (idx < sa->len) { sa->s[idx] = '\0'; sa->len = idx; } } /* '\0' → '\n' */ void sa_ztonl(stralloc *sa) { size_t idx; idx = byte_chr(sa->s, sa->len, '\0'); if (idx < sa->len) { sa->s[idx] = '\n'; sa->len = idx + 1; } } /* img url in sa → url */ int imgpath(stralloc *url, stralloc *sa) { json_stream j; enum json_type t; const char *key, *val; json_open_buffer(&j, sa->s, sa->len); json_set_streaming(&j, 0); t = json_next(&j); if (t != JSON_OBJECT) { json_close(&j); return -1; } while ((t = json_next(&j)) != JSON_DONE) { switch (t) { case JSON_STRING: key = json_get_string(&j, NULL); if (!strncmp(key, "post_url", MIN(strlen(key), strlen("post_url")))) { /* i'm not sure why there need to be two of these */ t = json_next(&j); t = json_next(&j); val = json_get_string(&j, NULL); url->len = 0; stralloc_cats(url, val); stralloc_0(url); return 0; } break; case JSON_OBJECT_END: goto done; break; } } done: return -1; } int http_recv(int fd, stralloc *sa) { char obuf[BUFFER_INSIZE]; buffer outb = BUFFER_INIT(&buffer_read, fd, obuf, BUFFER_INSIZE); if (skagetln(&outb, sa, '\n') < 0) return -1; if (sa->len < sizeof(HTTPOK) || !strncmp(sa->s, HTTPOK, sizeof(HTTPOK))) return -1; sa->len = 0; /* skip to the end of the header */ for (;;) { if (skagetln(&outb, sa, '\n') < 0) return -1; if (!strncmp(sa->s, "\r\n", 2)) { break; } sa->len = 0; } sa->len = 0; skagetln(&outb, sa, '\n'); // todo handle fuckery here stralloc_0(sa); return 0; } int http_send(int fd, char *id) { char buf[BUFFER_OUTSIZE]; buffer b = BUFFER_INIT(&buffer_write, fd, buf, BUFFER_OUTSIZE); buffer_putsnoflush(&b, "GET /api/links/"); buffer_putsnoflush(&b, id); buffer_putsnoflush(&b, ".json HTTP/1.0\r\n"); buffer_putsnoflush(&b, "Host: walltaker.joi.how\r\n"); buffer_putsnoflush(&b, "Connection: close\r\n"); buffer_putsnoflush(&b, "User-Agent: mvwt\r\n\r\n"); buffer_flush(&b); return 0; } int main(int argc, char *argv[]) { stralloc resp = STRALLOC_ZERO; stralloc img = STRALLOC_ZERO; stralloc currentimg = STRALLOC_ZERO; stralloc tmp = STRALLOC_ZERO; stralloc imhost = STRALLOC_ZERO; stralloc impath = STRALLOC_ZERO; stralloc imfile = STRALLOC_ZERO; PROG = "mvwtc"; if (argc != 2) strerr_dieusage(100, USAGE); if (http_send(7, argv[1]) < 0) strerr_diefu(111, "send http request"); if (http_recv(6, &resp) < 0) { stralloc_free(&resp); strerr_diefu(111, "recieve http response"); } fd_shutdown(7, 1); fd_close(7); fd_shutdown(6, 0); fd_close(6); if (imgpath(&img, &resp) < 0) { stralloc_free(&img); stralloc_free(&resp); strerr_dief(111, "json seems mangled"); } stralloc_free(&resp); if (opengetlnclose("current", ¤timg, '\n') >= 0) { sa_nltoz(¤timg); if (!strncmp(currentimg.s, img.s, MIN(currentimg.len, img.len))) { /* we don't need to do anything, just exit */ stralloc_free(¤timg); stralloc_free(&img); return 0; } } stralloc_copy(&tmp, &img); sa_ztonl(&tmp); if (!openwritenclose_suffix6("current", tmp.s, tmp.len, NULL, 0, "~")) { stralloc_free(&tmp); stralloc_free(¤timg); stralloc_free(&img); strerr_diefu(111, "write to current"); } stralloc_free(&tmp); url_hpn(&img, &imhost, &impath, &imfile); char const *wtimg_argv[] = { "s6-tlsclient", "-N", "--", imhost.s, "443", "mvwtimg", imhost.s, impath.s, imfile.s, 0 }; xexec(wtimg_argv); return 111; }