diff mcabber/src/fifo.c @ 1426:a64778f5f26b

Implement FIFO named command pipe
author Mikael Berthe <mikael@lilotux.net>
date Mon, 18 Feb 2008 22:59:37 +0100
parents
children a8eb9aba2ed2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/src/fifo.c	Mon Feb 18 22:59:37 2008 +0100
@@ -0,0 +1,174 @@
+/*
+ * fifo.c       -- Read commands from a named pipe
+ *
+ * Copyright (C) 2008 Mikael Berthe <mikael@lilotux.net>
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "commands.h"
+#include "logprint.h"
+#include "utils.h"
+
+#include "hbuf.h"   // For HBB_BLOCKSIZE
+
+static FILE *sfd;
+static char *fifo_name;
+
+
+//  fifo_init(fifo_path)
+// Create and open the FIFO file.
+// If fifo_path is NULL, reopen the current pipe.
+// Return 0 (success) or -1 (failure).
+int fifo_init(const char *fifo_path)
+{
+  struct stat buf;
+  int fd;
+  char *fifo_path_xp;
+
+  if (!sfd && !fifo_path)
+    return -1;  // Nothing to do...
+
+  if (sfd && !fifo_path) {  // We want to reinitialize the pipe
+    fclose(sfd);
+    sfd = NULL;
+    if (fifo_name)
+      goto fifo_init_open;
+  }
+  sfd = NULL;
+
+  fifo_path_xp = expand_filename(fifo_path);
+
+  if (!stat(fifo_path_xp, &buf)) {
+    if (!S_ISFIFO(buf.st_mode)) {
+      scr_LogPrint(LPRINT_LOGNORM, "WARNING: Cannot create the FIFO. "
+                   "%s already exists and is not a pipe", fifo_path_xp);
+      g_free(fifo_path_xp);
+      return -1;
+    }
+
+    if (unlink(fifo_path_xp)) {
+      scr_LogPrint(LPRINT_LOGNORM, "WARNING: Unable to unlink FIFO %s [%s]",
+                   fifo_path_xp, g_strerror(errno));
+      g_free(fifo_path_xp);
+      return -1;
+    }
+  }
+
+  if (mkfifo(fifo_path_xp, S_IWUSR | S_IRUSR)) {
+    scr_LogPrint(LPRINT_LOGNORM, "WARNING: Cannot create the FIFO [%s]",
+                 g_strerror(errno));
+    g_free(fifo_path_xp);
+    return -1;
+  }
+
+  fifo_name = fifo_path_xp;
+
+fifo_init_open:
+  fd = open(fifo_name, O_RDONLY | O_NONBLOCK);
+  if (!fd)
+    return -1;
+
+  sfd = fdopen(fd, "r");
+  if (fifo_path)
+    scr_LogPrint(LPRINT_LOGNORM, "FIFO initialized (%s)", fifo_name);
+  return 0;
+}
+
+//  fifo_deinit()
+// Close the current FIFO pipe and delete it.
+void fifo_deinit(void)
+{
+  if (sfd) {
+    fclose(sfd);
+    sfd = NULL;
+  }
+  if (fifo_name) {
+    unlink(fifo_name);
+    g_free(fifo_name);
+    fifo_name = NULL;
+  }
+}
+
+//  fifo_read()
+// Read a line from the FIFO pipe (if available), and execute it.
+void fifo_read(void)
+{
+  struct timeval tv;
+  fd_set fds;
+  char *getbuf;
+  char buf[HBB_BLOCKSIZE+1];
+  int fd;
+
+  if (!sfd) {
+    return;
+  }
+
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+
+  fd = fileno(sfd);
+
+  FD_ZERO(&fds);
+  FD_SET(fd, &fds);
+
+  select(fd + 1, &fds, NULL, NULL, &tv);
+
+  if (!FD_ISSET(fd, &fds)) {
+    return;
+  }
+
+  getbuf = fgets(buf, HBB_BLOCKSIZE, sfd);
+  if (getbuf) {
+    char *eol = buf;
+
+    // Strip trailing newlines
+    for ( ; *eol ; eol++)
+      ;
+    if (eol > buf)
+      eol--;
+    while (eol > buf && *eol == '\n')
+      *eol-- = 0;
+
+    scr_LogPrint(LPRINT_LOGNORM, "Executing FIFO command: %s", buf);
+    if (process_command(buf, TRUE) == 255)
+      mcabber_set_terminate_ui();
+  } else {
+    if (feof(sfd))
+      fifo_init(NULL);  // Reopen the FIFO on EOF
+  }
+}
+
+//  fifo_get_fd()
+// Return the FIFO file descriptor (-1 if none).
+int fifo_get_fd(void)
+{
+  if (sfd)
+    return fileno(sfd);
+  return -1;
+}
+
+/* vim: set expandtab cindent cinoptions=>2\:2(0:  For Vim users... */