summary refs log tree commit diff
path: root/url.c
diff options
context:
space:
mode:
authorC. McEnroe2020-02-08 19:04:25 -0500
committerC. McEnroe2020-02-08 19:04:25 -0500
commit9b9794df33488acc82529ecb9cfe478441f5f48a (patch)
tree253ea4cddecdea6fc50151bc49675ff27a056a99 /url.c
parentf502260dd0aa73b09bfbb7289b50a67592866166 (diff)
Implement URL opening
Diffstat (limited to 'url.c')
-rw-r--r--url.c73
1 files changed, 58 insertions, 15 deletions
diff --git a/url.c b/url.c
index 7790461..1396765 100644
--- a/url.c
+++ b/url.c
@@ -14,12 +14,15 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+#include <assert.h>
 #include <err.h>
+#include <errno.h>
 #include <regex.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sysexits.h>
+#include <unistd.h>
 
 #include "chat.h"
 
@@ -55,26 +58,31 @@ static void compile(void) {
 	errx(EX_SOFTWARE, "regcomp: %s: %s", buf, Pattern);
 }
 
+struct URL {
+	size_t id;
+	char *nick;
+	char *url;
+};
+
 enum { Cap = 32 };
 static struct {
-	size_t ids[Cap];
-	char *nicks[Cap];
-	char *urls[Cap];
+	struct URL urls[Cap];
 	size_t len;
 } ring;
+static_assert(!(Cap & (Cap - 1)), "Cap is power of two");
 
-static void push(size_t id, const char *nick, const char *url, size_t len) {
-	size_t i = ring.len++ % Cap;
-	free(ring.nicks[i]);
-	free(ring.urls[i]);
-	ring.ids[i] = id;
-	ring.nicks[i] = NULL;
+static void push(size_t id, const char *nick, const char *str, size_t len) {
+	struct URL *url = &ring.urls[ring.len++ % Cap];
+	free(url->nick);
+	free(url->url);
+	url->id = id;
+	url->nick = NULL;
 	if (nick) {
-		ring.nicks[i] = strdup(nick);
-		if (!ring.nicks[i]) err(EX_OSERR, "strdup");
+		url->nick = strdup(nick);
+		if (!url->nick) err(EX_OSERR, "strdup");
 	}
-	ring.urls[i] = strndup(url, len);
-	if (!ring.urls[i]) err(EX_OSERR, "strndup");
+	url->url = strndup(str, len);
+	if (!url->url) err(EX_OSERR, "strndup");
 }
 
 void urlScan(size_t id, const char *nick, const char *mesg) {
@@ -87,10 +95,45 @@ void urlScan(size_t id, const char *nick, const char *mesg) {
 	}
 }
 
+static const char *OpenBins[] = { "open", "xdg-open" };
+
+static void urlOpen(const char *url) {
+	pid_t pid = fork();
+	if (pid < 0) err(EX_OSERR, "fork");
+	if (pid) return;
+
+	close(STDIN_FILENO);
+	dup2(procPipe[1], STDOUT_FILENO);
+	dup2(procPipe[1], STDERR_FILENO);
+	for (size_t i = 0; i < ARRAY_LEN(OpenBins); ++i) {
+		execlp(OpenBins[i], OpenBins[i], url, NULL);
+		if (errno != ENOENT) {
+			warn("%s", OpenBins[i]);
+			_exit(EX_CONFIG);
+		}
+	}
+	warnx("no open utility found");
+	_exit(EX_CONFIG);
+}
+
 void urlOpenCount(size_t id, size_t count) {
-	// TODO
+	for (size_t i = 1; i <= Cap; ++i) {
+		const struct URL *url = &ring.urls[(ring.len - i) % Cap];
+		if (!url->url) break;
+		if (url->id != id) continue;
+		urlOpen(url->url);
+		if (!--count) break;
+	}
 }
 
 void urlOpenMatch(size_t id, const char *str) {
-	// TODO
+	for (size_t i = 1; i <= Cap; ++i) {
+		const struct URL *url = &ring.urls[(ring.len - i) % Cap];
+		if (!url->url) break;
+		if (url->id != id) continue;
+		if ((url->nick && !strcmp(url->nick, str)) || strstr(url->url, str)) {
+			urlOpen(url->url);
+			break;
+		}
+	}
 }