--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/separate-extcmd Fri Apr 02 02:29:43 2010 +0300
@@ -0,0 +1,453 @@
+diff -r bb1396d6ba03 mcabber/mcabber/Makefile.am
+--- a/mcabber/mcabber/Makefile.am Fri Apr 02 00:06:58 2010 +0300
++++ b/mcabber/mcabber/Makefile.am Fri Apr 02 01:50:48 2010 +0300
+@@ -7,7 +7,7 @@
+ xmpp.c xmpp.h xmpp_helper.c xmpp_helper.h xmpp_defines.h \
+ xmpp_iq.c xmpp_iq.h xmpp_iqrequest.c xmpp_iqrequest.h \
+ xmpp_muc.c xmpp_muc.h xmpp_s10n.c xmpp_s10n.h \
+- caps.c caps.h help.c help.h
++ caps.c caps.h help.c help.h extcmd.c extcmd.h
+
+ if OTR
+ mcabber_SOURCES += otr.c otr.h nohtml.c nohtml.h
+@@ -42,6 +42,7 @@
+ xmpp_iq.h xmpp_iqrequest.h \
+ xmpp_muc.h xmpp_s10n.h \
+ caps.h fifo.h help.h modules.h api.h \
++ extcmd.h \
+ $(top_srcdir)/include/config.h
+
+ if OTR
+diff -r bb1396d6ba03 mcabber/mcabber/extcmd.c
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/mcabber/mcabber/extcmd.c Fri Apr 02 01:50:48 2010 +0300
+@@ -0,0 +1,121 @@
++/*
++ * extcmd.c -- External event handler command
++ *
++ * Copyright (C) 2005-2010 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 <stdlib.h>
++#include <string.h>
++#include <sys/types.h>
++#include <unistd.h>
++#include <glib.h>
++
++#include "screen.h"
++#include "roster.h"
++#include "settings.h"
++#include "utils.h"
++#include "utf8.h"
++
++static char *extcmd = NULL;
++
++// hk_ext_cmd_init()
++// Initialize external command variable.
++// Can be called with parameter NULL to reset and free memory
++void hk_ext_cmd_init(const char *command)
++{
++ if (extcmd) {
++ g_free(extcmd);
++ extcmd = NULL;
++ }
++ if (command)
++ extcmd = expand_filename(command);
++}
++
++// hk_ext_cmd()
++// Launch an external command (process) for the given event.
++// For now, data should be NULL.
++void hk_ext_cmd(const char *name, const char *arg_type, const char *arg_info, const char *data)
++{
++ pid_t pid;
++ char *arg_data = NULL;
++ char *datafname = NULL;
++
++ if (!arg_type || !arg_info) return;
++
++ if (*name && settings_opt_get_int("eventcmd_use_nickname"))
++ name = roster_getname(name);
++
++ if (data && settings_opt_get_int("event_log_files")) {
++ int fd;
++ const char *prefix;
++ char *prefix_xp = NULL;
++ char *data_locale;
++
++ data_locale = from_utf8(data);
++ prefix = settings_opt_get("event_log_dir");
++ if (prefix)
++ prefix = prefix_xp = expand_filename(prefix);
++ else
++ prefix = ut_get_tmpdir();
++ datafname = g_strdup_printf("%s/mcabber-%d.XXXXXX", prefix, getpid());
++ g_free(prefix_xp);
++
++ // XXX Some old systems may require us to set umask first.
++ fd = mkstemp(datafname);
++ if (fd == -1) {
++ g_free(datafname);
++ datafname = NULL;
++ scr_LogPrint(LPRINT_LOGNORM,
++ "Unable to create temp file for external command.");
++ } else {
++ size_t data_locale_len = strlen(data_locale);
++ ssize_t a = write(fd, data_locale, data_locale_len);
++ ssize_t b = write(fd, "\n", 1);
++ if ((size_t)a != data_locale_len || b != 1) {
++ g_free(datafname);
++ datafname = NULL;
++ scr_LogPrint(LPRINT_LOGNORM,
++ "Unable to write to temp file for external command.");
++ }
++ close(fd);
++ arg_data = datafname;
++ }
++ g_free(data_locale);
++ }
++
++ if ((pid=fork()) == -1) {
++ scr_LogPrint(LPRINT_LOGNORM, "Fork error, cannot launch external command.");
++ g_free(datafname);
++ return;
++ }
++
++ if (pid == 0) { // child
++ // Close standard file descriptors
++ close(STDIN_FILENO);
++ close(STDOUT_FILENO);
++ close(STDERR_FILENO);
++ if (execl(extcmd, extcmd, arg_type, arg_info, name, arg_data,
++ (char *)NULL) == -1) {
++ // scr_LogPrint(LPRINT_LOGNORM, "Cannot execute external command.");
++ exit(1);
++ }
++ }
++ g_free(datafname);
++}
++
++/* vim: set expandtab cindent cinoptions=>2\:2(0: For Vim users... */
+diff -r bb1396d6ba03 mcabber/mcabber/extcmd.h
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/mcabber/mcabber/extcmd.h Fri Apr 02 01:50:48 2010 +0300
+@@ -0,0 +1,15 @@
++#ifndef __MCABBER_EXTCMD_H__
++#define __MCABBER_EXTCMD_H__ 1
++
++#define EXT_CMD_TYPE_MESSAGE "MSG"
++#define EXT_CMD_TYPE_STATUS "STATUS"
++#define EXT_CMD_TYPE_UNREAD "UNREAD"
++
++#define EXT_CMD_INFO_RECEIVED "IN"
++#define EXT_CMD_INFO_SENT "OUT"
++#define EXT_CMD_INFO_GROUPCHAT "MUC"
++
++void hk_ext_cmd_init(const char *command);
++void hk_ext_cmd(const char *bjid, const char *type, const char *info, const char *data);
++
++#endif
+diff -r bb1396d6ba03 mcabber/mcabber/hooks.c
+--- a/mcabber/mcabber/hooks.c Fri Apr 02 00:06:58 2010 +0300
++++ b/mcabber/mcabber/hooks.c Fri Apr 02 01:50:48 2010 +0300
+@@ -24,6 +24,7 @@
+ #include <string.h>
+ #include <sys/types.h>
+ #include <unistd.h>
++#include <ctype.h>
+
+ #include "hooks.h"
+ #include "screen.h"
+@@ -35,6 +36,7 @@
+ #include "utf8.h"
+ #include "commands.h"
+ #include "main.h"
++#include "extcmd.h"
+
+ #ifdef MODULES_ENABLE
+ #include <glib.h>
+@@ -177,8 +179,6 @@
+ }
+ #endif
+
+-static char *extcmd;
+-
+ static const char *COMMAND_ME = "/me ";
+
+ void hk_message_in(const char *bjid, const char *resname,
+@@ -195,7 +195,6 @@
+ char *wmsg = NULL, *bmsg = NULL, *mmsg = NULL;
+ GSList *roster_usr;
+ unsigned mucnicklen = 0;
+- const char *ename = NULL;
+ gboolean attention = FALSE, mucprivmsg = FALSE;
+
+ if (encrypted == ENCRYPTED_PGP)
+@@ -359,19 +358,6 @@
+ (!is_room || (is_groupchat && log_muc_conf && !timestamp)))
+ hlog_write_message(bjid, timestamp, 0, wmsg);
+
+- if (settings_opt_get_int("events_ignore_active_window") &&
+- current_buddy && scr_get_chatmode()) {
+- gpointer bud = BUDDATA(current_buddy);
+- if (bud) {
+- const char *cjid = buddy_getjid(bud);
+- if (cjid && !strcasecmp(cjid, bjid))
+- active_window = TRUE;
+- }
+- }
+-
+- if (settings_opt_get_int("eventcmd_use_nickname"))
+- ename = roster_getname(bjid);
+-
+ // Display the sender in the log window
+ if ((!is_groupchat) && !(message_flags & HBB_PREFIX_ERR) &&
+ settings_opt_get_int("log_display_sender")) {
+@@ -395,12 +381,24 @@
+ }
+ #endif
+
++ if (settings_opt_get_int("events_ignore_active_window") &&
++ current_buddy && scr_get_chatmode()) {
++ gpointer bud = BUDDATA(current_buddy);
++ if (bud) {
++ const char *cjid = buddy_getjid(bud);
++ if (cjid && !strcasecmp(cjid, bjid))
++ active_window = TRUE;
++ }
++ }
++
+ // External command
+ // - We do not call hk_ext_cmd() for history lines in MUC
+ // - We do call hk_ext_cmd() for private messages in a room
+ // - We do call hk_ext_cmd() for messages to the current window
+ if (!active_window && ((is_groupchat && !timestamp) || !is_groupchat))
+- hk_ext_cmd(ename ? ename : bjid, (is_groupchat ? 'G' : 'M'), 'R', wmsg);
++ hk_ext_cmd(bjid, EXT_CMD_TYPE_MESSAGE,
++ is_groupchat ? EXT_CMD_INFO_GROUPCHAT : EXT_CMD_INFO_RECEIVED,
++ wmsg);
+
+ // Beep, if enabled:
+ // - if it's a private message
+@@ -478,7 +476,7 @@
+ #endif
+
+ // External command
+- hk_ext_cmd(bjid, 'M', 'S', NULL);
++ hk_ext_cmd(bjid, EXT_CMD_TYPE_MESSAGE, EXT_CMD_INFO_SENT, NULL);
+
+ g_free(bmsg);
+ g_free(mmsg);
+@@ -493,10 +491,7 @@
+ char *bn;
+ char *logsmsg;
+ const char *rn = (resname ? resname : "");
+- const char *ename = NULL;
+-
+- if (settings_opt_get_int("eventcmd_use_nickname"))
+- ename = roster_getname(bjid);
++ char newstatus[2] = { '?', '\0' };
+
+ oldstat = roster_getstatus(bjid, resname);
+
+@@ -548,27 +543,28 @@
+ scr_draw_roster();
+ hlog_write_status(bjid, timestamp, status, status_msg);
+
++ newstatus[0] = imstatus2char[status];
++
+ #ifdef MODULES_ENABLE
+ {
+ char os[2] = " \0";
+- char ns[2] = " \0";
+ hk_arg_t args[] = {
+ { "jid", bjid },
+ { "resource", rn },
+ { "old_status", os },
+- { "new_status", ns },
++ { "new_status", newstatus },
+ { "message", status_msg ? status_msg : "" },
+ { NULL, NULL },
+ };
+ os[0] = imstatus2char[oldstat];
+- ns[0] = imstatus2char[status];
+
+ hk_run_handlers(HOOK_STATUS_CHANGE, args);
+ }
+ #endif
+
+ // External command
+- hk_ext_cmd(ename ? ename : bjid, 'S', imstatus2char[status], NULL);
++ newstatus[0] = toupper(newstatus[0]);
++ hk_ext_cmd(bjid, EXT_CMD_TYPE_STATUS, newstatus, status_msg);
+ }
+
+ void hk_mystatuschange(time_t timestamp, enum imstatus old_status,
+@@ -695,127 +691,8 @@
+ /* Call external command */
+ str_unread = g_strdup_printf("%u %u %u %u", unread_count, attention_count,
+ muc_unread, muc_attention);
+- hk_ext_cmd("", 'U', (guchar)MIN(255, unread_count), str_unread);
++ hk_ext_cmd("", EXT_CMD_TYPE_UNREAD, str_unread, NULL);
+ g_free(str_unread);
+ }
+
+-
+-/* External commands */
+-
+-// hk_ext_cmd_init()
+-// Initialize external command variable.
+-// Can be called with parameter NULL to reset and free memory.
+-void hk_ext_cmd_init(const char *command)
+-{
+- if (extcmd) {
+- g_free(extcmd);
+- extcmd = NULL;
+- }
+- if (command)
+- extcmd = expand_filename(command);
+-}
+-
+-// hk_ext_cmd()
+-// Launch an external command (process) for the given event.
+-// For now, data should be NULL.
+-void hk_ext_cmd(const char *bjid, guchar type, guchar info, const char *data)
+-{
+- pid_t pid;
+- const char *arg_type = NULL;
+- const char *arg_info = NULL;
+- const char *arg_data = NULL;
+- char status_str[2];
+- char *datafname = NULL;
+-
+- if (!extcmd) return;
+-
+- // Prepare arg_* (external command parameters)
+- switch (type) {
+- case 'M': /* Normal message */
+- arg_type = "MSG";
+- if (info == 'R')
+- arg_info = "IN";
+- else if (info == 'S')
+- arg_info = "OUT";
+- break;
+- case 'G': /* Groupchat message */
+- arg_type = "MSG";
+- arg_info = "MUC";
+- break;
+- case 'S': /* Status change */
+- arg_type = "STATUS";
+- if (strchr(imstatus2char, tolower(info))) {
+- status_str[0] = toupper(info);
+- status_str[1] = 0;
+- arg_info = status_str;
+- }
+- break;
+- case 'U': /* Unread buffer count */
+- arg_type = "UNREAD";
+- arg_info = data;
+- break;
+- default:
+- return;
+- }
+-
+- if (!arg_type || !arg_info) return;
+-
+- if (strchr("MG", type) && data && settings_opt_get_int("event_log_files")) {
+- int fd;
+- const char *prefix;
+- char *prefix_xp = NULL;
+- char *data_locale;
+-
+- data_locale = from_utf8(data);
+- prefix = settings_opt_get("event_log_dir");
+- if (prefix)
+- prefix = prefix_xp = expand_filename(prefix);
+- else
+- prefix = ut_get_tmpdir();
+- datafname = g_strdup_printf("%s/mcabber-%d.XXXXXX", prefix, getpid());
+- g_free(prefix_xp);
+-
+- // XXX Some old systems may require us to set umask first.
+- fd = mkstemp(datafname);
+- if (fd == -1) {
+- g_free(datafname);
+- datafname = NULL;
+- scr_LogPrint(LPRINT_LOGNORM,
+- "Unable to create temp file for external command.");
+- } else {
+- size_t data_locale_len = strlen(data_locale);
+- ssize_t a = write(fd, data_locale, data_locale_len);
+- ssize_t b = write(fd, "\n", 1);
+- if ((size_t)a != data_locale_len || b != 1) {
+- g_free(datafname);
+- datafname = NULL;
+- scr_LogPrint(LPRINT_LOGNORM,
+- "Unable to write to temp file for external command.");
+- }
+- close(fd);
+- arg_data = datafname;
+- }
+- g_free(data_locale);
+- }
+-
+- if ((pid=fork()) == -1) {
+- scr_LogPrint(LPRINT_LOGNORM, "Fork error, cannot launch external command.");
+- g_free(datafname);
+- return;
+- }
+-
+- if (pid == 0) { // child
+- // Close standard file descriptors
+- close(STDIN_FILENO);
+- close(STDOUT_FILENO);
+- close(STDERR_FILENO);
+- if (execl(extcmd, extcmd, arg_type, arg_info, bjid, arg_data,
+- (char *)NULL) == -1) {
+- // scr_LogPrint(LPRINT_LOGNORM, "Cannot execute external command.");
+- exit(1);
+- }
+- }
+- g_free(datafname);
+-}
+-
+ /* vim: set expandtab cindent cinoptions=>2\:2(0 sw=2 ts=2: For Vim users... */
+diff -r bb1396d6ba03 mcabber/mcabber/hooks.h
+--- a/mcabber/mcabber/hooks.h Fri Apr 02 00:06:58 2010 +0300
++++ b/mcabber/mcabber/hooks.h Fri Apr 02 01:50:48 2010 +0300
+@@ -62,9 +62,6 @@
+ void hk_unread_list_change(guint unread_count, guint attention_count,
+ guint muc_unread, guint muc_attention);
+
+-void hk_ext_cmd_init(const char *command);
+-void hk_ext_cmd(const char *bjid, guchar type, guchar info, const char *data);
+-
+ #endif /* __MCABBER_HOOKS_H__ */
+
+ /* vim: set expandtab cindent cinoptions=>2\:2(0 sw=2 ts=2: For Vim users... */
+diff -r bb1396d6ba03 mcabber/mcabber/main.c
+--- a/mcabber/mcabber/main.c Fri Apr 02 00:06:58 2010 +0300
++++ b/mcabber/mcabber/main.c Fri Apr 02 01:50:48 2010 +0300
+@@ -45,6 +45,7 @@
+ #include "xmpp.h"
+ #include "help.h"
+ #include "events.h"
++#include "extcmd.h"
+
+ #ifndef MODULES_ENABLE
+ # include "fifo.h"