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(