/*
 * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
 * See README for License detail, AUTHORS for developers list.
 *
 * 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/>.
 */

/* fifo.c: FIFO pipe for WeeChat remote control */


#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "weechat.h"
#include "fifo.h"
#include "command.h"
#include "log.h"
#include "weeconfig.h"
#include "../gui/gui.h"


int weechat_fifo = -1;
char *weechat_fifo_filename = NULL;
char *weechat_fifo_unterminated = NULL;


/*
 * fifo_create: create FIFO pipe for remote control
 */

void
fifo_create ()
{
    int filename_length;
    
    if (cfg_irc_fifo_pipe)
    {
        /* build FIFO filename: "<weechat_home>/weechat_fifo_" + process PID */
        if (!weechat_fifo_filename)
        {
            filename_length = strlen (weechat_home) + 64;
            weechat_fifo_filename = (char *) malloc (filename_length * sizeof (char));
            snprintf (weechat_fifo_filename, filename_length, "%s/weechat_fifo_%d",
                      weechat_home, (int) getpid());
        }
        
        /* create FIFO pipe, writable for user only */
        if ((weechat_fifo = mkfifo (weechat_fifo_filename, 0600)) != 0)
        {
            weechat_fifo = -1;
            gui_printf (NULL,
                        _("%s unable to create FIFO pipe for remote control (%s)\n"),
                        WEECHAT_ERROR, weechat_fifo_filename);
            weechat_log_printf (_("%s unable to create FIFO pipe for "
                                  "remote control (%s)\n"),
                                WEECHAT_ERROR, weechat_fifo_filename);
            return;
        }
        
        /* open FIFO pipe in read-only (for WeeChat), non nlobking mode */
        if ((weechat_fifo = open (weechat_fifo_filename, O_RDONLY | O_NONBLOCK)) == -1)
        {
            gui_printf (NULL,
                        _("%s unable to open FIFO pipe (%s) for reading\n"),
                        WEECHAT_ERROR, weechat_fifo_filename);
            weechat_log_printf (_("%s unable to open FIFO pipe (%s) for reading\n"),
                                WEECHAT_ERROR, weechat_fifo_filename);
            return;
        }
        
        weechat_log_printf (_("FIFO pipe is open\n"));
    }
}

/*
 * fifo_exec: execute a command/text received by FIFO pipe
 */

void
fifo_exec (char *text)
{
    char *pos_msg, *pos;
    t_irc_server *ptr_server;
    t_irc_channel *ptr_channel;
    
    pos = NULL;
    ptr_server = NULL;
    ptr_channel = NULL;
    
    /* look for server/channel at beginning of text */
    /* text may be: "server,channel *text" or "server *text" or "*text" */
    if (text[0] == '*')
    {
        pos_msg = text + 1;
        if (gui_current_window->buffer->has_input)
        {
            ptr_server = GUI_SERVER(gui_current_window->buffer);
            ptr_channel = GUI_CHANNEL(gui_current_window->buffer);
        }
        else
        {
            ptr_server = GUI_SERVER(gui_buffers);
            ptr_channel = NULL;
        }
    }
    else
    {
        pos_msg = strstr (text, " *");
        if (!pos_msg)
        {
            irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
            gui_printf (NULL, _("%s invalid text received on FIFO pipe\n"),
                        WEECHAT_WARNING);
            return;
        }
        pos_msg[0] = '\0';
        pos = pos_msg - 1;
        pos_msg += 2;
        while ((pos >= text) && (pos[0] == ' '))
        {
            pos[0] = '\0';
            pos--;
        }
        
        if (text[0])
        {
            pos = strchr (text, ',');
            if (pos)
                pos[0] = '\0';
            ptr_server = irc_server_search (text);
            if (!ptr_server || !ptr_server->buffer)
            {
                irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
                gui_printf (NULL, _("%s server \"%s\" not found (FIFO pipe data)\n"),
                            WEECHAT_WARNING, text);
                return;
            }
            if (ptr_server && pos)
            {
                ptr_channel = irc_channel_search_any (ptr_server, pos + 1);
                if (!ptr_channel)
                {
                    irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
                    gui_printf (NULL,
                                _("%s channel \"%s\" not found (FIFO pipe data)\n"),
                                WEECHAT_WARNING, pos + 1);
                    return;
                }
            }
        }
    }
    
    user_command (ptr_server, ptr_channel, pos_msg, 0);
}

/*
 * fifo_read: read data in FIFO pipe
 */

void
fifo_read ()
{
    static char buffer[4096 + 2];
    char *buf2, *pos, *ptr_buf, *next_ptr_buf;
    int num_read;
    
    num_read = read (weechat_fifo, buffer, sizeof (buffer) - 2);
    if (num_read > 0)
    {
        buffer[num_read] = '\0';
        
        buf2 = NULL;
        ptr_buf = buffer;
        if (weechat_fifo_unterminated)
        {
            buf2 = (char *) malloc (strlen (weechat_fifo_unterminated) +
                strlen (buffer) + 1);
            if (buf2)
            {
                strcpy (buf2, weechat_fifo_unterminated);
                strcat (buf2, buffer);
            }
            ptr_buf = buf2;
            free (weechat_fifo_unterminated);
            weechat_fifo_unterminated = NULL;
        }
        
        while (ptr_buf && ptr_buf[0])
        {
            next_ptr_buf = NULL;
            pos = strstr (ptr_buf, "\r\n");
            if (pos)
            {
                pos[0] = '\0';
                next_ptr_buf = pos + 2;
            }
            else
            {
                pos = strstr (ptr_buf, "\n");
                if (pos)
                {
                    pos[0] = '\0';
                    next_ptr_buf = pos + 1;
                }
                else
                {
                    weechat_fifo_unterminated = strdup (ptr_buf);
                    ptr_buf = NULL;
                    next_ptr_buf = NULL;
                }
            }
            
            if (ptr_buf)
                fifo_exec (ptr_buf);
            
            ptr_buf = next_ptr_buf;
        }
        
        if (buf2)
            free (buf2);
    }
    else
    {
        if (num_read < 0)
        {
            gui_printf (NULL,
                        _("%s error reading FIFO pipe, closing it\n"),
                        WEECHAT_ERROR);
            weechat_log_printf (_("%s error reading FIFO pipe, closing it\n"),
                                WEECHAT_ERROR);
            fifo_remove ();
        }
        else
        {
            close (weechat_fifo);
            weechat_fifo = open (weechat_fifo_filename, O_RDONLY | O_NONBLOCK);
        }
    }
}

/*
 * fifo_remove: remove FIFO pipe
 */

void
fifo_remove ()
{
    if (weechat_fifo != -1)
    {
        /* close FIFO pipe */
        close (weechat_fifo);
        weechat_fifo = -1;
    }
    
    /* remove FIFO from disk */
    if (weechat_fifo_filename)
        unlink (weechat_fifo_filename);
    
    if (weechat_fifo_unterminated)
    {
        free (weechat_fifo_unterminated);
        weechat_fifo_unterminated = NULL;
    }
    
    if (weechat_fifo_filename)
    {
        free (weechat_fifo_filename);
        weechat_fifo_filename = NULL;
    }
    
    weechat_log_printf (_("FIFO pipe is closed\n"));
}


syntax highlighted by Code2HTML, v. 0.9.1