about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--catgirl.113
-rw-r--r--chat.c4
-rw-r--r--chat.h29
-rw-r--r--scripts/notify-send.scpt9
-rw-r--r--ui.c34
5 files changed, 72 insertions, 17 deletions
diff --git a/catgirl.1 b/catgirl.1
index 672abfc..b7a9559 100644
--- a/catgirl.1
+++ b/catgirl.1
@@ -1,4 +1,4 @@
-.Dd February 11, 2020
+.Dd February 12, 2020
 .Dt CATGIRL 1
 .Os
 .
@@ -11,6 +11,7 @@
 .Op Fl Rev
 .Op Fl C Ar copy
 .Op Fl H Ar hash
+.Op Fl N Ar send
 .Op Fl O Ar open
 .Op Fl S Ar bind
 .Op Fl a Ar auth
@@ -66,6 +67,16 @@ The default is the first available of
 Set the initial value of
 the nick color hash function.
 .
+.It Fl N Ar util , Cm notify = Ar util
+Send notifications using a utility.
+Use more than once to add arguments to
+.Ar util .
+Two additional arguments are passed to
+.Ar util :
+a title and a description,
+appropriate for
+.Xr notify-send 1 .
+.
 .It Fl O Ar util , Cm open = Ar util
 Set the utility used by
 .Ic /open .
diff --git a/chat.c b/chat.c
index c0950fb..dbd2784 100644
--- a/chat.c
+++ b/chat.c
@@ -94,11 +94,12 @@ int main(int argc, char *argv[]) {
 	const char *user = NULL;
 	const char *real = NULL;
 
-	const char *Opts = "!C:H:O:RS:a:c:eh:j:k:n:p:r:s:u:vw:";
+	const char *Opts = "!C:H:N:O:RS:a:c:eh:j:k:n:p:r:s:u:vw:";
 	const struct option LongOpts[] = {
 		{ "insecure", no_argument, NULL, '!' },
 		{ "copy", required_argument, NULL, 'C' },
 		{ "hash", required_argument, NULL, 'H' },
+		{ "notify", required_argument, NULL, 'N' },
 		{ "open", required_argument, NULL, 'O' },
 		{ "restrict", no_argument, NULL, 'R' },
 		{ "bind", required_argument, NULL, 'S' },
@@ -124,6 +125,7 @@ int main(int argc, char *argv[]) {
 			break; case '!': insecure = true;
 			break; case 'C': utilPush(&urlCopyUtil, optarg);
 			break; case 'H': hashInit = strtoul(optarg, NULL, 0);
+			break; case 'N': utilPush(&uiNotifyUtil, optarg);
 			break; case 'O': utilPush(&urlOpenUtil, optarg);
 			break; case 'R': self.restricted = true;
 			break; case 'S': bind = optarg;
diff --git a/chat.h b/chat.h
index ed6dc2f..fb7bf61 100644
--- a/chat.h
+++ b/chat.h
@@ -146,7 +146,22 @@ const char *commandIsNotice(size_t id, const char *input);
 const char *commandIsAction(size_t id, const char *input);
 void commandComplete(void);
 
+enum { UtilCap = 16 };
+struct Util {
+	size_t argc;
+	const char *argv[UtilCap];
+};
+
+static inline void utilPush(struct Util *util, const char *arg) {
+	if (1 + util->argc < UtilCap) {
+		util->argv[util->argc++] = arg;
+	} else {
+		errx(EX_CONFIG, "too many utility arguments");
+	}
+}
+
 enum Heat { Cold, Warm, Hot };
+extern struct Util uiNotifyUtil;
 void uiInit(void);
 void uiShow(void);
 void uiHide(void);
@@ -196,20 +211,6 @@ void completeClear(size_t id);
 size_t completeID(const char *str);
 enum Color completeColor(size_t id, const char *str);
 
-enum { UtilCap = 16 };
-struct Util {
-	size_t argc;
-	const char *argv[UtilCap];
-};
-
-static inline void utilPush(struct Util *util, const char *arg) {
-	if (1 + util->argc < UtilCap) {
-		util->argv[util->argc++] = arg;
-	} else {
-		errx(EX_CONFIG, "too many utility arguments");
-	}
-}
-
 extern struct Util urlOpenUtil;
 extern struct Util urlCopyUtil;
 void urlScan(size_t id, const char *nick, const char *mesg);
diff --git a/scripts/notify-send.scpt b/scripts/notify-send.scpt
new file mode 100644
index 0000000..5630440
--- /dev/null
+++ b/scripts/notify-send.scpt
@@ -0,0 +1,9 @@
+#!/usr/bin/osascript
+
+on run argv
+	if count of argv is 2 then
+		display notification (item 2 of argv) with title (item 1 of argv)
+	else
+		display notification (item 1 of argv)
+	end if
+end run
diff --git a/ui.c b/ui.c
index 97f81b3..0bf619d 100644
--- a/ui.c
+++ b/ui.c
@@ -530,6 +530,35 @@ static int wordWrap(WINDOW *win, const char *str) {
 	return lines;
 }
 
+struct Util uiNotifyUtil;
+static void notify(size_t id, const char *str) {
+	if (!uiNotifyUtil.argc) return;
+
+	struct Util util = uiNotifyUtil;
+	utilPush(&util, idNames[id]);
+	size_t len = 0;
+	char buf[1024] = "";
+	while (*str && len < sizeof(buf)) {
+		size_t run;
+		struct Style style = Reset;
+		styleParse(&style, &str, &run);
+		len += snprintf(&buf[len], sizeof(buf) - len, "%.*s", (int)run, str);
+		str += run;
+	}
+	utilPush(&util, buf);
+
+	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);
+	execvp(util.argv[0], (char *const *)util.argv);
+	warn("%s", util.argv[0]);
+	_exit(EX_CONFIG);
+}
+
 void uiWrite(size_t id, enum Heat heat, const time_t *src, const char *str) {
 	struct Window *window = windowFor(id);
 	time_t clock = (src ? *src : time(NULL));
@@ -548,7 +577,10 @@ void uiWrite(size_t id, enum Heat heat, const time_t *src, const char *str) {
 	lines += wordWrap(window->pad, str);
 	window->unreadLines += lines;
 	if (window->scroll) windowScroll(window, lines);
-	if (heat > Warm) beep();
+	if (window->mark && heat > Warm) {
+		beep();
+		notify(id, str);
+	}
 }
 
 void uiFormat(