Added SILC Thread Queue API
[runtime.git] / apps / irssi / src / fe-common / core / fe-exec.c
index bc8f46919168cbe3cc2e73482b601ad8208fe63c..3fa8899551c4b745562bd975ea34bfca5d6dde58 100644 (file)
@@ -1,7 +1,7 @@
 /*
  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
@@ -19,6 +19,7 @@
 */
 
 #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;
@@ -47,11 +73,11 @@ static EXEC_WI_REC *exec_wi_create(WINDOW_REC *window, PROCESS_REC *rec)
 
        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;
 
@@ -60,21 +86,6 @@ static EXEC_WI_REC *exec_wi_create(WINDOW_REC *window, PROCESS_REC *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;
@@ -177,6 +188,7 @@ static void process_destroy(PROCESS_REC *rec, int status)
 
        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);
 }
@@ -337,7 +349,7 @@ static void process_exec(PROCESS_REC *rec, const char *cmd)
 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);
@@ -365,11 +377,12 @@ static void sig_exec_input_reader(PROCESS_REC *rec)
 }
 
 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
@@ -384,6 +397,7 @@ static void handle_exec(const char *args, GHashTable *optlist,
        }
 
        target = NULL;
+       target_server = NULL;
        notice = FALSE;
 
        if (g_hash_table_lookup(optlist, "in") != NULL) {
@@ -402,16 +416,22 @@ static void handle_exec(const char *args, GHashTable *optlist,
                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;
        }
 
@@ -443,6 +463,8 @@ static void handle_exec(const char *args, GHashTable *optlist,
                         /* 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;
                }
 
@@ -458,10 +480,8 @@ static void handle_exec(const char *args, GHashTable *optlist,
                        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 =
@@ -485,12 +505,20 @@ static void handle_exec(const char *args, GHashTable *optlist,
 
         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);
@@ -518,7 +546,7 @@ static void cmd_exec(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
        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);
        }
 }
@@ -526,12 +554,17 @@ static void cmd_exec(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
 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);
@@ -555,24 +588,37 @@ static void sig_exec_input(PROCESS_REC *rec, const char *text)
        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);
        }
 }
 
@@ -590,17 +636,10 @@ static void sig_window_destroyed(WINDOW_REC *window)
        }
 }
 
-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);
@@ -610,13 +649,12 @@ static void event_text(const char *data, SERVER_REC *server, EXEC_WI_REC *item)
 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);
 }
 
@@ -636,6 +674,5 @@ void fe_exec_deinit(void)
         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);
 }