From 925aa4bedb20236dd0e7b75414e6bc05960bb4a6 Mon Sep 17 00:00:00 2001
From: Daniel Carl <danielcarl@gmx.de>
Date: Thu, 13 Nov 2014 00:00:38 +0100
Subject: [PATCH] Allow to control vimb by fifo file (#144).

---
 config.mk        |   1 +
 doc/vimb.1       |  13 ++++--
 src/config.def.h |   2 +
 src/io.c         | 110 +++++++++++++++++++++++++++++++++++++++++++++++
 src/io.h         |  32 ++++++++++++++
 src/main.c       |  19 +++++++-
 src/main.h       |   1 +
 7 files changed, 173 insertions(+), 5 deletions(-)
 create mode 100644 src/io.c
 create mode 100644 src/io.h

diff --git a/config.mk b/config.mk
index a1f6fa8..9930aed 100644
--- a/config.mk
+++ b/config.mk
@@ -31,6 +31,7 @@ PROJECT_UCFIRST = $(shell echo '${PROJECT}' | awk '{for(i=1;i<=NF;i++){$$i=toupp
 CPPFLAGS  = -DVERSION=\"${VERSION}\"
 CPPFLAGS += -DPROJECT=\"${PROJECT}\" -DPROJECT_UCFIRST=\"${PROJECT_UCFIRST}\"
 CPPFLAGS += -D_XOPEN_SOURCE=500
+CPPFLAGS += -D_POSIX_SOURCE
 ifeq ($(USEGTK3), 1)
 CPPFLAGS += -DHAS_GTK3
 CPPFLAGS += -DGSEAL_ENABLE
diff --git a/doc/vimb.1 b/doc/vimb.1
index 447f29f..9158905 100644
--- a/doc/vimb.1
+++ b/doc/vimb.1
@@ -15,10 +15,7 @@ vimb - Vim Browser - A modal web browser based on webkit, inspired by vim the
 great editor.
 .SH SYNOPSIS
 .SY vimb
-.OP \-hkv
-.OP \-C cmd
-.OP \-c config
-.OP \-e winid
+.OP OPTIONS
 .RI [ URI "|" file "|" - ]
 .YS
 .SH DESCRIPTION
@@ -55,6 +52,10 @@ Show help options.
 Run vimb in kiosk mode with nearly no keybindings, not inputbox and no context
 menu.
 .TP
+.B \-n, \-\-fifo-name
+If given vimb will create a control fifo in vimb's config directory
+named 'vimb-fifo-{name}'.
+.TP
 .B "\-v, \-\-version"
 Print build and version information.
 .SH MODES
@@ -1403,6 +1404,10 @@ Contains the pid of the running vimb instance.
 Holds the X-Window id of the vim window or of the embedding window if vimb is
 started with -e option.
 .TP
+.B VIMB_FILE
+Holds the full path to the control fifo, if vimb is compiled with FIFO feature
+and started with `--fifo-name' option.
+.TP
 .B http_proxy
 If this variable is set to an none empty value, and the configuration option
 `proxy' is enabled, this will be used as http proxy. If the proxy URL has no
diff --git a/src/config.def.h b/src/config.def.h
index e99b68e..ce0e5cb 100644
--- a/src/config.def.h
+++ b/src/config.def.h
@@ -52,6 +52,8 @@
 #define FEATURE_AUTOCMD
 /* enable the :auto-response-header feature */
 #define FEATURE_ARH
+/* allow to use fifo to remote control vimb */
+#define FEATURE_FIFO
 
 /* time in seconds after that message will be removed from inputbox if the
  * message where only temporary */
diff --git a/src/io.c b/src/io.c
new file mode 100644
index 0000000..c1095aa
--- /dev/null
+++ b/src/io.c
@@ -0,0 +1,110 @@
+/**
+ * vimb - a webkit based vim like browser.
+ *
+ * Copyright (C) 2012-2014 Daniel Carl
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ */
+
+#include "config.h"
+#ifdef FEATURE_FIFO
+#include "io.h"
+#include "main.h"
+#include "map.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+extern VbCore vb;
+
+static gboolean fifo_watch(GIOChannel *gio, GIOCondition condition);
+
+
+gboolean io_init_fifo(const char *name)
+{
+    char *fname, *path;
+
+    /* create fifo in directory as vimb-fifo-$PID */
+    fname = g_strdup_printf(PROJECT "-fifo-%s", name);
+    path  = g_build_filename(g_get_user_config_dir(), PROJECT, fname, NULL);
+    g_free(fname);
+
+    /* if the file already exists - remove this first */
+    if (g_file_test(path, G_FILE_TEST_IS_REGULAR)) {
+        unlink(path);
+    }
+
+    if (mkfifo(path, 0666) == 0) {
+        GError *error    = NULL;
+        /* use r+ to avoid blocking caused by wait of a writer */
+        GIOChannel *chan = g_io_channel_new_file(path, "r+", &error);
+        if (chan) {
+            if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc)fifo_watch, NULL)) {
+                /* don't free path - because we want to keep the value in
+                 * vb.state.fifo_path still accessible */
+                vb.state.fifo_path = path;
+                g_setenv("VIMB_FIFO", path, TRUE);
+
+                return true;
+            }
+        } else {
+            g_warning ("Can't open fifo: %s", error->message);
+            g_error_free(error);
+        }
+    } else {
+        g_warning("Can't create fifo %s", path);
+    }
+    g_free(path);
+
+    return false;
+}
+
+void io_cleanup(void)
+{
+    if (vb.state.fifo_path) {
+        if (unlink(vb.state.fifo_path) == -1) {
+            g_warning("Can't remove fifo %s", vb.state.fifo_path);
+        }
+        g_free(vb.state.fifo_path);
+        vb.state.fifo_path = NULL;
+    }
+}
+
+static gboolean fifo_watch(GIOChannel *gio, GIOCondition condition)
+{
+    char *line;
+    GIOStatus ret;
+    GError *err = NULL;
+
+    if (condition & G_IO_HUP) {
+        g_error("fifo: read end of pipe died");
+    }
+
+    if (!gio) {
+        g_error("fifo: GIOChannel broken");
+    }
+
+    ret = g_io_channel_read_line(gio, &line, NULL, NULL, &err);
+    if (ret == G_IO_STATUS_ERROR) {
+        g_error("fifo: error reading from fifo: %s", err->message);
+        g_error_free(err);
+    }
+
+    map_handle_string(line, true);
+    g_free(line);
+
+    return true;
+}
+
+#endif
diff --git a/src/io.h b/src/io.h
new file mode 100644
index 0000000..fdddbf5
--- /dev/null
+++ b/src/io.h
@@ -0,0 +1,32 @@
+/**
+ * vimb - a webkit based vim like browser.
+ *
+ * Copyright (C) 2012-2014 Daniel Carl
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ */
+
+#include "config.h"
+#ifdef FEATURE_FIFO
+
+#ifndef _IO_H
+#define _IO_H
+
+#include <glib.h>
+
+gboolean io_init_fifo(const char *dir);
+void io_cleanup(void);
+
+#endif /* end of include guard: _IO_H */
+#endif
diff --git a/src/main.c b/src/main.c
index 342c7d5..301fcf1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -44,6 +44,7 @@
 #include "js.h"
 #include "autocmd.h"
 #include "arh.h"
+#include "io.h"
 
 /* variables */
 static char **args;
@@ -434,6 +435,9 @@ void vb_quit(gboolean force)
 #ifdef FEATURE_ARH
     arh_free(vb.config.autoresponseheader);
 #endif
+#ifdef FEATURE_FIFO
+    io_cleanup();
+#endif
 
     g_slist_free_full(vb.config.cmdargs, g_free);
 
@@ -1527,6 +1531,9 @@ static gboolean autocmdOptionArgFunc(const gchar *option_name, const gchar *valu
 int main(int argc, char *argv[])
 {
     static char *winid = NULL;
+#ifdef FEATURE_FIFO
+    static char *fifo_name = NULL;
+#endif
     static gboolean ver = false;
     static GError *err;
     char *pid;
@@ -1536,6 +1543,9 @@ int main(int argc, char *argv[])
         {"config", 'c', 0, G_OPTION_ARG_STRING, &vb.config.file, "Custom configuration file", NULL},
         {"embed", 'e', 0, G_OPTION_ARG_STRING, &winid, "Reparents to window specified by xid", NULL},
         {"kiosk", 'k', 0, G_OPTION_ARG_NONE, &vb.config.kioskmode, "Run in kiosk mode", NULL},
+#ifdef FEATURE_FIFO
+        {"fifo-name", 'n', 0, G_OPTION_ARG_STRING, &fifo_name, "Name used to create control fifo", NULL},
+#endif
         {"version", 'v', 0, G_OPTION_ARG_NONE, &ver, "Print version", NULL},
         {NULL}
     };
@@ -1559,7 +1569,7 @@ int main(int argc, char *argv[])
         vb.embed = strtol(winid, NULL, 0);
     }
 
-    pid = g_strdup_printf("%d", getpid());
+    pid = g_strdup_printf("%d", (int)getpid());
     g_setenv("VIMB_PID", pid, true);
     g_free(pid);
 
@@ -1581,6 +1591,13 @@ int main(int argc, char *argv[])
         vb_load_uri(&(Arg){VB_TARGET_CURRENT, argv[argc - 1]});
     }
 
+#ifdef FEATURE_FIFO
+    /* setup the control fifo - quit vimb if this failed */
+    if (fifo_name && *fifo_name && !io_init_fifo(fifo_name)) {
+        return EXIT_FAILURE;
+    }
+#endif
+
     /* Run the main GTK+ event loop */
     gtk_main();
 
diff --git a/src/main.h b/src/main.h
index 0144a54..2aa6e95 100644
--- a/src/main.h
+++ b/src/main.h
@@ -304,6 +304,7 @@ typedef struct {
 #ifdef FEATURE_SEARCH_HIGHLIGHT
     int             search_matches;         /* number of matches search results */
 #endif
+    char            *fifo_path;             /* holds the path to the control fifo */
 } State;
 
 typedef struct {
-- 
2.20.1