view mcabber/src/fifo.c @ 1461:8fa24a6d1a93

Improve Remote Controlling Clients The XEP recommends adding the node to the IQ response. Some clients seem not to understand the answer when it is omitted. Problem reported by Rhaamo and js (thanks to js for spotting the node issue!).
author Mikael Berthe <mikael@lilotux.net>
date Sat, 12 Apr 2008 13:35:03 +0200
parents a8eb9aba2ed2
children eefa0ae248d8
line wrap: on
line source

/*
 * 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 "settings.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) {
    guint logflag;
    char *eol = buf;

    // Strip trailing newlines
    for ( ; *eol ; eol++)
      ;
    if (eol > buf)
      eol--;
    while (eol > buf && *eol == '\n')
      *eol-- = 0;

    if (settings_opt_get_int("fifo_hide_commands"))
      logflag = LPRINT_LOG;
    else
      logflag = LPRINT_LOGNORM;
    scr_LogPrint(logflag, "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... */