/*
fe-exec.c : irssi
- Copyright (C) 2000 Timo Sirainen
+ Copyright (C) 2000-2001 Timo Sirainen
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
*/
#include "module.h"
+#include "modules.h"
#include "signals.h"
#include "commands.h"
#include "pidwait.h"
#include "misc.h"
#include "levels.h"
+#include "servers.h"
+#include "channels.h"
+#include "queries.h"
+
#include "printtext.h"
#include "fe-exec.h"
#include "fe-windows.h"
#include <signal.h>
#include <sys/wait.h>
-static GSList *processes;
+GSList *processes;
static int signal_exec_input;
+static void exec_wi_destroy(EXEC_WI_REC *rec)
+{
+ g_return_if_fail(rec != NULL);
+
+ if (rec->destroying) return;
+ rec->destroying = TRUE;
+
+ rec->process->target_item = NULL;
+ if (window_item_window((WI_ITEM_REC *) rec) != NULL)
+ window_item_destroy((WI_ITEM_REC *) rec);
+
+ MODULE_DATA_DEINIT(rec);
+ g_free(rec->visible_name);
+ g_free(rec);
+}
+
+static const char *exec_get_target(WI_ITEM_REC *item)
+{
+ return ((EXEC_WI_REC *) item)->visible_name;
+}
+
static EXEC_WI_REC *exec_wi_create(WINDOW_REC *window, PROCESS_REC *rec)
{
EXEC_WI_REC *item;
item = g_new0(EXEC_WI_REC, 1);
item->type = module_get_uniq_id_str("WINDOW ITEM TYPE", "EXEC");
- item->name = rec->name != NULL ?
- g_strdup_printf("%%%s", rec->name) :
+ item->destroy = (void (*) (WI_ITEM_REC *)) exec_wi_destroy;
+ item->get_target = exec_get_target;
+ item->visible_name = rec->name != NULL ? g_strdup(rec->name) :
g_strdup_printf("%%%d", rec->id);
- item->window = window;
item->createtime = time(NULL);
item->process = rec;
return item;
}
-static void exec_wi_destroy(EXEC_WI_REC *rec)
-{
- g_return_if_fail(rec != NULL);
-
- if (rec->destroying) return;
- rec->destroying = TRUE;
-
- if (window_item_window((WI_ITEM_REC *) rec) != NULL)
- window_item_destroy((WI_ITEM_REC *) rec);
-
- MODULE_DATA_DEINIT(rec);
- g_free(rec->name);
- g_free(rec);
-}
-
static int process_get_new_id(void)
{
PROCESS_REC *rec;
g_free_not_null(rec->name);
g_free_not_null(rec->target);
+ g_free_not_null(rec->target_server);
g_free(rec->args);
g_free(rec);
}
static void sig_exec_input_reader(PROCESS_REC *rec)
{
char tmpbuf[512], *str;
- unsigned int recvlen;
+ gsize recvlen;
int err, ret;
g_return_if_fail(rec != NULL);
}
static void handle_exec(const char *args, GHashTable *optlist,
- WI_ITEM_REC *item)
+ SERVER_REC *server, WI_ITEM_REC *item)
{
PROCESS_REC *rec;
- char *target;
- int notice, signum, interactive;
+ SERVER_REC *target_server;
+ char *target, *level;
+ int notice, signum, interactive, target_nick, target_channel;
/* check that there's no unknown options. we allowed them
because signals can be used as options, but there should be
}
target = NULL;
+ target_server = NULL;
notice = FALSE;
if (g_hash_table_lookup(optlist, "in") != NULL) {
return;
/* common options */
+ target_channel = target_nick = FALSE;
if (g_hash_table_lookup(optlist, "out") != NULL) {
/* redirect output to active channel/query */
if (item == NULL)
cmd_return_error(CMDERR_NOT_JOINED);
- target = item->name;
+ target = (char *) window_item_get_target(item);
+ target_server = item->server;
+ target_channel = IS_CHANNEL(item);
+ target_nick = IS_QUERY(item);
} else if (g_hash_table_lookup(optlist, "msg") != NULL) {
/* redirect output to /msg <nick> */
target = g_hash_table_lookup(optlist, "msg");
+ target_server = server;
} else if (g_hash_table_lookup(optlist, "notice") != NULL) {
target = g_hash_table_lookup(optlist, "notice");
+ target_server = server;
notice = TRUE;
}
/* redirect output to target */
g_free_and_null(rec->target);
rec->target = g_strdup(target);
+ rec->target_server = target_server == NULL ? NULL :
+ g_strdup(target_server->tag);
rec->notice = notice;
}
g_free_and_null(rec->target);
rec->target_win = active_win;
- if (rec->target_item != NULL) {
+ if (rec->target_item != NULL)
exec_wi_destroy(rec->target_item);
- rec->target_item = NULL;
- }
if (interactive) {
rec->target_item =
rec->id = process_get_new_id();
rec->target = g_strdup(target);
+ rec->target_server = target_server == NULL ? NULL :
+ g_strdup(target_server->tag);
rec->target_win = active_win;
+ rec->target_channel = target_channel;
+ rec->target_nick = target_nick;
rec->args = g_strdup(args);
rec->notice = notice;
rec->silent = g_hash_table_lookup(optlist, "-") != NULL;
+ rec->quiet = g_hash_table_lookup(optlist, "quiet") != NULL;
rec->name = g_strdup(g_hash_table_lookup(optlist, "name"));
+ level = g_hash_table_lookup(optlist, "level");
+ rec->level = level == NULL ? MSGLEVEL_CLIENTCRAP : level2bits(level);
+
rec->read_tag = g_input_add(rec->in, G_INPUT_READ,
(GInputFunction) sig_exec_input_reader,
rec);
if (cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
"exec", &optlist, &args)) {
- handle_exec(args, optlist, item);
+ handle_exec(args, optlist, server, item);
cmd_params_free(free_arg);
}
}
static void sig_pidwait(void *pid, void *statusp)
{
PROCESS_REC *rec;
+ char *str;
int status = GPOINTER_TO_INT(statusp);
rec = process_find_pid(GPOINTER_TO_INT(pid));
if (rec == NULL) return;
- /* process exited */
+ /* process exited - print the last line if
+ there wasn't a newline at end. */
+ if (line_split("\n", 1, &str, &rec->databuf) > 0 && *str != '\0')
+ signal_emit_id(signal_exec_input, 2, rec, str);
+
if (!rec->silent) {
if (WIFSIGNALED(status)) {
status = WTERMSIG(status);
SERVER_REC *server;
char *str;
+ if (rec->quiet)
+ return;
+
item = NULL;
server = NULL;
if (rec->target != NULL) {
- item = window_item_find(NULL, rec->target);
- server = item != NULL ? item->server :
- active_win->active_server;
+ if (rec->target_server != NULL) {
+ server = server_find_tag(rec->target_server);
+ if (server == NULL) {
+ /* disconnected - target is lost */
+ return;
+ }
+ item = NULL;
+ } else {
+ item = window_item_find(NULL, rec->target);
+ server = item != NULL ? item->server :
+ active_win->active_server;
+ }
- str = g_strconcat(rec->target, " ", text, NULL);
+ str = g_strconcat(rec->target_nick ? "-nick " :
+ rec->target_channel ? "-channel " : "",
+ rec->target, " ", text, NULL);
signal_emit(rec->notice ? "command notice" : "command msg",
3, str, server, item);
g_free(str);
} else if (rec->target_item != NULL) {
- printtext(NULL, rec->target_item->name, MSGLEVEL_CLIENTCRAP,
- "%s", text);
+ printtext(NULL, rec->target_item->visible_name,
+ rec->level, "%s", text);
} else {
- printtext_window(rec->target_win, MSGLEVEL_CLIENTCRAP,
- "%s", text);
+ printtext_window(rec->target_win, rec->level, "%s", text);
}
}
}
}
-static void sig_window_item_destroyed(WINDOW_REC *window, EXEC_WI_REC *item)
-{
- if (IS_EXEC_WI(item)) {
- item->process->target_item = NULL;
- exec_wi_destroy(item);
- }
-}
-
static void event_text(const char *data, SERVER_REC *server, EXEC_WI_REC *item)
{
- if (!IS_EXEC_WI(item)) return;
+ if (!IS_EXEC_WI(item))
+ return;
net_sendbuffer_send(item->process->out, data, strlen(data));
net_sendbuffer_send(item->process->out, "\n", 1);
void fe_exec_init(void)
{
command_bind("exec", NULL, (SIGNAL_FUNC) cmd_exec);
- command_set_options("exec", "!- interactive nosh +name out +msg +notice +in window close");
+ command_set_options("exec", "!- interactive nosh +name out +msg +notice +in window close +level quiet");
signal_exec_input = signal_get_uniq_id("exec input");
signal_add("pidwait", (SIGNAL_FUNC) sig_pidwait);
signal_add("exec input", (SIGNAL_FUNC) sig_exec_input);
signal_add("window destroyed", (SIGNAL_FUNC) sig_window_destroyed);
- signal_add("window item destroy", (SIGNAL_FUNC) sig_window_item_destroyed);
signal_add_first("send text", (SIGNAL_FUNC) event_text);
}
signal_remove("pidwait", (SIGNAL_FUNC) sig_pidwait);
signal_remove("exec input", (SIGNAL_FUNC) sig_exec_input);
signal_remove("window destroyed", (SIGNAL_FUNC) sig_window_destroyed);
- signal_remove("window item destroy", (SIGNAL_FUNC) sig_window_item_destroyed);
signal_remove("send text", (SIGNAL_FUNC) event_text);
}