separate-extcmd
changeset 0 633272cbb544
child 14 020fbfb5441c
--- /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"