util  Check-in [6b40270f28]

Overview
Comment:add newtab
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 6b40270f2843f2cbfc588dc51f60abcdaaeb1649f2aa3c97a31361c8811eca93
User & Date: lexi on 2019-11-05 16:14:39
Other Links: manifest | tags
Context
2019-11-05
16:27
nitpick check-in: 2a975fabe3 user: lexi tags: trunk
16:14
add newtab check-in: 6b40270f28 user: lexi tags: trunk
2019-10-17
20:03
reorganize dumbass directory structure check-in: c29fe4718a user: lexi tags: trunk
Changes

Added newtab.c version [bf8e7ec053].















































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* [ʞ] newtab.c
 *  ~ lexi hale <lexi@hale.su>
 *  $ cc -Ofast newtab.c -onewtab \
 *      [-D_default_qutebrowser_location=/...]
 *  $ ./newtab [example.net]
 *  © AGPLv3
 *  ? may god have mercy on my soul.
 *    i wrote this because qutebrowser, being a python
 *    abomination, takes an absurdly fucking long time
 *    to load, even when there's already an instance
 *    running and i just want a new goddamn tab. it
 *    turns out, qutebrowser publishes an inane IPC
 *    mechanism, in which JSON (i know!!) written to a
 *    unix domain socket (I KNOW) can send signals to
 *    a running qutebrowser process. newtab checks if
 *    there's a running qutebrowser process and sends
 *    the appropriate IPC signal if so. otherwise, it
 *    execs a new qutebrowser instance.
 *
 *    it takes a single argument, the URI of a page to
 *    navigate to. if launched without an argument,
 *    newtab simply opens a blank new tab. simple
 *    enough, right? but why write it in C? to talk to
 *    a goddammned python application, of all things?
 *    well, i was originally going to do this in a
 *    bash script with socat, but then i pulled up the
 *    socat manpage and immediately decided it would
 *    be faster to implement the damn thing in C, and
 *    performance would be better anyway. i think it
 *    is fair to say that i was correct.
 *
 *    so, that's half the story. the code quality is
 *    the other half. i'm going to be straight with
 *    you: i wrote this sleep-deprived at 7am because
 *    i'd stayed up all night with my boyfriend who's
 *    still remote-working on German time because his
 *    employers are kind of assholes. i'm aware that's
 *    not an excuse and i apologize sincerely. if
 *    anyone wants to submit a MR to tidy up this
 *    abomination without sacrificing performance, i
 *    would welcome it gratefully. */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <dirent.h>
#include <unistd.h>
#define _POSIX_C_SOURCE 200809L
#include <string.h>

#define ssz(str) (str), (sizeof str)
#define dupl(x) x,x

#ifndef _default_qutebrowser_location
#	define _default_qutebrowser_location "/usr/bin/qutebrowser"
#endif

#define jstr(val) "\"" val "\""
#define j(key, val) jstr(#key) ": " val
#define json_msg_start "{" \
			j(protocol_version, "1") "," \
			j(target_arg, jstr("")) "," \
			jstr("args")": [\""
#define json_msg_end "\"]}\n"

enum status {
	ok,
	start_instance,
	fail_xdg_null,
	fail_find,
};

const char* errors [] = {
	[ok] = NULL,
	[start_instance] = NULL,
	[fail_xdg_null] = "$XDG_RUNTIME_DIR is not set - cannot locate IPC socket",
	[fail_find] = "cannot find qutebrowser - is your $PATH set correctly?",
};

enum status
transmit(const char* uri) {
	const char* const run = getenv("XDG_RUNTIME_DIR");
	if (run == NULL) return fail_xdg_null;

	struct sockaddr_un srv = {
		.sun_family = AF_UNIX,
	} ; {
		/* fuck this fuck this fuck this fuck this */
		char* end = stpncpy(srv.sun_path, run, sizeof srv.sun_path);
		end = stpncpy(end, ssz("/qutebrowser/"));
		DIR* qb = opendir(srv.sun_path);
		if (!qb) return start_instance;
		struct dirent* ent;
		while (ent = readdir(qb)) {
			if (ent == NULL) return start_instance;
			if (ent -> d_name[0] != '.') break;
		}
		if (ent == NULL) return start_instance;
		end = stpncpy(end, ent->d_name,
				(sizeof srv.sun_path) - (end - srv.sun_path));
		closedir(qb);
	}

	int sock = socket(AF_UNIX, SOCK_STREAM, 0);
	if (connect(sock, (struct sockaddr*)&srv, sizeof srv) != 0)
		return start_instance;

	const char msg_blank [] = json_msg_start json_msg_end;
	const size_t extra = uri != NULL ? strlen(uri) : 0;
	char msg_start [(sizeof json_msg_start) + extra];

	const size_t msgsz = sizeof msg_blank + extra - 1;
	const char*  msg;
	if (uri == NULL) msg = msg_blank; else {
		strcpy(msg_start, json_msg_start);
		strcpy(msg_start + (sizeof json_msg_start) - 1, uri);
		strcpy(msg_start + (sizeof json_msg_start) - 1 + extra, json_msg_end);
		msg = msg_start;
	}

	const char* cur = msg;
	while(cur < msg + msgsz)
		cur += write(sock, cur, msgsz - (cur - msg));

	close(sock);

	return ok;
}

int main(int argc, char** argv) {
	if (argc > 2) {
		printf("\x1b[1musage:\x1b[m %s [uri]\n", argv[0]);
	} else {
		const char* uri = argc < 2 ? NULL : argv[1];
		enum status st = transmit(uri);
		if (st == start_instance) {
			if (!fork()) {
				execl(dupl(_default_qutebrowser_location), uri, NULL);
				execl(dupl("/usr/local/bin/qutebrowser"), uri, NULL);
				execlp(dupl("qutebrowser"), uri, NULL);
				st = fail_find;
			} else {
				return start_instance;
			}
		}
		if (errors[st] != NULL) printf("\x1b[1;31m(error)\x1b[m %s\n", errors[st]);
		return st;
	}
}