1
0
mirror of https://github.com/weechat/weechat.git synced 2026-07-01 07:16:37 +02:00

trigger: add trigger plugin

This commit is contained in:
Sebastien Helleu
2014-01-25 13:29:03 +01:00
parent a0bf3938f1
commit 30942f7f62
28 changed files with 3807 additions and 516 deletions
+31
View File
@@ -0,0 +1,31 @@
#
# Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org>
#
# This file is part of WeeChat, the extensible chat client.
#
# WeeChat 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.
#
# WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
#
ADD_LIBRARY(trigger MODULE
trigger.c trigger.h
trigger-buffer.c trigger-buffer.h
trigger-callback.c trigger-callback.h
trigger-command.c trigger-command.h
trigger-completion.c trigger-completion.h
trigger-config.c trigger-config.h)
SET_TARGET_PROPERTIES(trigger PROPERTIES PREFIX "")
TARGET_LINK_LIBRARIES(trigger)
INSTALL(TARGETS trigger LIBRARY DESTINATION ${LIBDIR}/plugins)
+42
View File
@@ -0,0 +1,42 @@
#
# Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org>
#
# This file is part of WeeChat, the extensible chat client.
#
# WeeChat 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.
#
# WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
#
AM_CPPFLAGS = -DLOCALEDIR=\"$(datadir)/locale\" $(TRIGGER_CFLAGS)
libdir = ${weechat_libdir}/plugins
lib_LTLIBRARIES = trigger.la
trigger_la_SOURCES = trigger.c \
trigger.h \
trigger-buffer.c \
trigger-buffer.h \
trigger-callback.c \
trigger-callback.h \
trigger-command.c \
trigger-command.h \
trigger-completion.c \
trigger-completion.h \
trigger-config.c \
trigger-config.h
trigger_la_LDFLAGS = -module -no-undefined
trigger_la_LIBADD = $(TRIGGER_LFLAGS)
EXTRA_DIST = CMakeLists.txt
+180
View File
@@ -0,0 +1,180 @@
/*
* trigger-buffer.c - debug buffer for triggers
*
* Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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.
*
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../weechat-plugin.h"
#include "trigger.h"
#include "trigger-buffer.h"
struct t_gui_buffer *trigger_buffer = NULL;
/*
* Callback called for each entry in hashtable.
*/
void
trigger_buffer_hashtable_map_cb (void *data,
struct t_hashtable *hashtable,
const void *key, const void *value)
{
const char *value_type;
char *value_no_color;
/* make C compiler happy */
(void) data;
(void) hashtable;
value_type = weechat_hashtable_get_string (hashtable, "type_values");
if (!value_type)
return;
if (strcmp (value_type, "string") == 0)
{
value_no_color = weechat_string_remove_color ((const char *)value, NULL);
weechat_printf_tags (trigger_buffer, "no_trigger",
"\t %s: \"%s\"",
(char *)key,
(value_no_color) ? value_no_color : (const char *)value);
if (value_no_color)
free (value_no_color);
}
else if (strcmp (value_type, "pointer") == 0)
{
weechat_printf_tags (trigger_buffer, "no_trigger",
"\t %s: 0x%lx",
(char *)key,
value);
}
}
/*
* Displays a hashtable on trigger buffer.
*/
void
trigger_buffer_display_hashtable (const char *name,
struct t_hashtable *hashtable)
{
if (!trigger_buffer)
return;
weechat_printf_tags (trigger_buffer, "no_trigger", " %s:", name);
weechat_hashtable_map (hashtable, &trigger_buffer_hashtable_map_cb, NULL);
}
/*
* Callback for user data in trigger buffer.
*/
int
trigger_buffer_input_cb (void *data, struct t_gui_buffer *buffer,
const char *input_data)
{
/* make C compiler happy */
(void) data;
/* close buffer */
if (strcmp (input_data, "q") == 0)
{
weechat_buffer_close (buffer);
return WEECHAT_RC_OK;
}
return WEECHAT_RC_OK;
}
/*
* Callback called when trigger buffer is closed.
*/
int
trigger_buffer_close_cb (void *data, struct t_gui_buffer *buffer)
{
/* make C compiler happy */
(void) data;
(void) buffer;
trigger_buffer = NULL;
return WEECHAT_RC_OK;
}
/*
* Restore buffer callbacks (input and close) for buffer created by trigger
* plugin.
*/
void
trigger_buffer_set_callbacks ()
{
struct t_gui_buffer *ptr_buffer;
ptr_buffer = weechat_buffer_search (TRIGGER_PLUGIN_NAME,
TRIGGER_BUFFER_NAME);
if (ptr_buffer)
{
trigger_buffer = ptr_buffer;
weechat_buffer_set_pointer (trigger_buffer, "close_callback",
&trigger_buffer_close_cb);
weechat_buffer_set_pointer (trigger_buffer, "input_callback",
&trigger_buffer_input_cb);
}
}
/*
* Opens script buffer.
*/
void
trigger_buffer_open (int switch_to_buffer)
{
if (!trigger_buffer)
{
trigger_buffer = weechat_buffer_new (TRIGGER_BUFFER_NAME,
&trigger_buffer_input_cb, NULL,
&trigger_buffer_close_cb, NULL);
/* failed to create buffer ? then return */
if (!trigger_buffer)
return;
weechat_buffer_set (trigger_buffer, "title", _("Trigger monitor"));
if (!weechat_buffer_get_integer (trigger_buffer, "short_name_is_set"))
weechat_buffer_set (trigger_buffer, "short_name", TRIGGER_BUFFER_NAME);
weechat_buffer_set (trigger_buffer, "localvar_set_type", "debug");
weechat_buffer_set (trigger_buffer, "localvar_set_server", TRIGGER_BUFFER_NAME);
weechat_buffer_set (trigger_buffer, "localvar_set_channel", TRIGGER_BUFFER_NAME);
weechat_buffer_set (trigger_buffer, "localvar_set_no_log", "1");
/* disable all highlights on this buffer */
weechat_buffer_set (trigger_buffer, "highlight_words", "-");
}
if (switch_to_buffer)
weechat_buffer_set (trigger_buffer, "display", "1");
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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.
*
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __WEECHAT_TRIGGER_BUFFER_H
#define __WEECHAT_TRIGGER_BUFFER_H 1
#define TRIGGER_BUFFER_NAME "monitor"
struct t_gui_buffer *trigger_buffer;
extern void trigger_buffer_display_hashtable (const char *name,
struct t_hashtable *hashtable);
extern void trigger_buffer_set_callbacks ();
extern void trigger_buffer_open (int switch_to_buffer);
#endif /* __WEECHAT_TRIGGER_BUFFER_H */
+597
View File
@@ -0,0 +1,597 @@
/*
* trigger-callback.c - callbacks for triggers
*
* Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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.
*
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "../weechat-plugin.h"
#include "trigger.h"
#include "trigger-buffer.h"
/* one hashtable by hook, used in callback to evaluate "conditions" */
struct t_hashtable *trigger_callback_hashtable_options = NULL;
/*
* Checks conditions for a trigger.
*
* Returns:
* 1: conditions are true (or no condition set in trigger)
* 0: conditions are false
*/
int
trigger_callback_check_conditions (struct t_trigger *trigger,
struct t_hashtable *pointers,
struct t_hashtable *extra_vars)
{
const char *conditions;
char *value;
int rc;
conditions = weechat_config_string (trigger->options[TRIGGER_OPTION_CONDITIONS]);
if (!conditions || !conditions[0])
return 1;
value = weechat_string_eval_expression (conditions,
pointers,
extra_vars,
trigger_callback_hashtable_options);
rc = (value && (strcmp (value, "1") == 0));
if (value)
free (value);
return rc;
}
/*
* Replaces text using one or more regex in the trigger.
*
* Note: result must be freed after use.
*/
char *
trigger_callback_replace_regex (struct t_trigger *trigger, const char *string)
{
char *temp, *res;
int i;
if (trigger->regex_count == 0)
return strdup (string);
res = NULL;
for (i = 0; i < trigger->regex_count; i++)
{
temp = weechat_string_replace_regex ((res) ? res : string,
trigger->regex[i].regex,
trigger->regex[i].replace_eval);
if (!temp)
return res;
res = temp;
}
return res;
}
/*
* Executes the trigger command(s).
*/
void
trigger_callback_run_command (struct t_trigger *trigger,
struct t_gui_buffer *buffer,
struct t_hashtable *pointers,
struct t_hashtable *extra_vars)
{
const char *command;
char *command_eval, **commands, **ptr_command;
command = weechat_config_string (trigger->options[TRIGGER_OPTION_COMMAND]);
if (!command || !command[0])
return;
command_eval = weechat_string_eval_expression (command, pointers,
extra_vars, NULL);
if (command_eval)
{
commands = weechat_string_split_command (command_eval, ';');
if (commands)
{
for (ptr_command = commands; *ptr_command; ptr_command++)
{
/* display debug info on trigger buffer */
if (trigger_buffer)
{
weechat_printf_tags (trigger_buffer, "no_trigger",
"\t running command \"%s\"",
*ptr_command);
}
weechat_command (buffer, *ptr_command);
}
weechat_string_free_split_command (commands);
trigger->hook_count_cmd++;
}
free (command_eval);
}
}
/*
* Callback for a signal hooked.
*/
int
trigger_callback_signal_cb (void *data, const char *signal,
const char *type_data, void *signal_data)
{
struct t_trigger *trigger;
struct t_hashtable *extra_vars;
const char *command, *ptr_signal_data;
char str_data[128], *signal_data2;
int rc;
/* get trigger pointer, return immediately if not found or trigger running */
trigger = (struct t_trigger *)data;
if (!trigger || trigger->hook_running)
return WEECHAT_RC_OK;
trigger->hook_count_cb++;
trigger->hook_running = 1;
extra_vars = NULL;
rc = trigger_return_code[weechat_config_integer (trigger->options[TRIGGER_OPTION_RETURN_CODE])];
/*
* in a signal, the only possible action is to execute a command;
* so if the command is empty, just exit without checking conditions
*/
command = weechat_config_string (trigger->options[TRIGGER_OPTION_COMMAND]);
if (!command || !command[0])
goto end;
/* create hashtable */
extra_vars = weechat_hashtable_new (32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL,
NULL);
if (!extra_vars)
goto end;
/* add data in hashtable used for conditions/replace/command */
weechat_hashtable_set (extra_vars, "tg_signal", signal);
if (strcmp (type_data, WEECHAT_HOOK_SIGNAL_STRING) == 0)
{
ptr_signal_data = (const char *)signal_data;
}
else if (strcmp (type_data, WEECHAT_HOOK_SIGNAL_INT) == 0)
{
snprintf (str_data, sizeof (str_data),
"%d", *((int *)signal_data));
ptr_signal_data = str_data;
}
else if (strcmp (type_data, WEECHAT_HOOK_SIGNAL_POINTER) == 0)
{
str_data[0] = '\0';
if (signal_data)
{
snprintf (str_data, sizeof (str_data),
"0x%lx", (long unsigned int)signal_data);
}
ptr_signal_data = str_data;
}
weechat_hashtable_set (extra_vars, "tg_signal_data", ptr_signal_data);
/* display debug info on trigger buffer */
if (!trigger_buffer && (weechat_trigger_plugin->debug >= 1))
trigger_buffer_open (0);
if (trigger_buffer)
{
weechat_printf_tags (trigger_buffer, "no_trigger",
"signal\t%s%s",
weechat_color ("chat_channel"),
trigger->name);
weechat_printf_tags (trigger_buffer, "no_trigger",
"\t signal_data: \"%s%s\"",
ptr_signal_data,
weechat_color ("reset"));
trigger_buffer_display_hashtable ("extra_vars", extra_vars);
}
/* check conditions */
if (!trigger_callback_check_conditions (trigger, NULL, extra_vars))
goto end;
/* replace text with regex */
if (trigger->regex_count > 0)
{
signal_data2 = trigger_callback_replace_regex (trigger, ptr_signal_data);
if (signal_data2)
{
weechat_hashtable_set (extra_vars, "tg_signal_data", signal_data2);
free (signal_data2);
}
}
/* execute command */
trigger_callback_run_command (trigger, NULL, NULL, extra_vars);
end:
if (extra_vars)
weechat_hashtable_free (extra_vars);
trigger->hook_running = 0;
return rc;
}
/*
* Callback for a hsignal hooked.
*/
int
trigger_callback_hsignal_cb (void *data, const char *signal,
struct t_hashtable *hashtable)
{
(void) data;
(void) signal;
(void) hashtable;
return WEECHAT_RC_OK;
}
/*
* Callback for a modifier hooked.
*/
char *
trigger_callback_modifier_cb (void *data, const char *modifier,
const char *modifier_data, const char *string)
{
struct t_trigger *trigger;
struct t_hashtable *extra_vars;
const char *command;
char *string_modified, *pos, *pos2, *plugin_name, *buffer_name;
char *buffer_full_name, *tags;
int no_trigger, length;
no_trigger = 0;
/* get trigger pointer, return immediately if not found or trigger running */
trigger = (struct t_trigger *)data;
if (!trigger || trigger->hook_running)
return NULL;
trigger->hook_count_cb++;
trigger->hook_running = 1;
extra_vars = NULL;
string_modified = NULL;
/*
* in a modifier, the only possible actions are regex or command;
* so if both are empty, just exit without checking conditions
*/
command = weechat_config_string (trigger->options[TRIGGER_OPTION_COMMAND]);
if ((!command || !command[0]) && !trigger->regex)
goto end;
/* create hashtable */
extra_vars = weechat_hashtable_new (32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL,
NULL);
if (!extra_vars)
goto end;
/* add data in hashtable used for conditions/replace/command */
weechat_hashtable_set (extra_vars, "tg_modifier", modifier);
weechat_hashtable_set (extra_vars, "tg_modifier_data", modifier_data);
weechat_hashtable_set (extra_vars, "tg_string", string);
/* add special variables for a WeeChat message */
if (strcmp (modifier, "weechat_print") == 0)
{
pos = strchr (modifier_data, ';');
if (pos)
{
plugin_name = weechat_strndup (modifier_data, pos - modifier_data);
if (plugin_name)
{
weechat_hashtable_set (extra_vars, "tg_plugin", plugin_name);
pos++;
pos2 = strchr (pos, ';');
if (pos2)
{
buffer_name = weechat_strndup (pos, pos2 - pos);
if (buffer_name)
{
length = strlen (plugin_name) + 1 + strlen (buffer_name) + 1;
buffer_full_name = malloc (length);
if (buffer_full_name)
{
snprintf (buffer_full_name, length,
"%s.%s", plugin_name, buffer_name);
weechat_hashtable_set (extra_vars, "tg_buffer",
buffer_full_name);
free (buffer_full_name);
}
free (buffer_name);
}
pos2++;
if (pos2[0])
{
length = 1 + strlen (pos2) + 1 + 1;
tags = malloc (length);
if (tags)
{
snprintf (tags, length, ",%s,", pos2);
weechat_hashtable_set (extra_vars, "tg_tags", tags);
if (strstr (tags, ",no_trigger,"))
no_trigger = 1;
free (tags);
}
}
}
free (plugin_name);
}
}
}
/*
* ignore this modifier if "no_trigger" was in tags
* (for modifier "weechat_print")
*/
if (no_trigger)
goto end;
/* display debug info on trigger buffer */
if (!trigger_buffer && (weechat_trigger_plugin->debug >= 1))
trigger_buffer_open (0);
if (trigger_buffer)
{
weechat_printf_tags (trigger_buffer, "no_trigger",
"modifier\t%s%s",
weechat_color ("chat_channel"),
trigger->name);
weechat_printf_tags (trigger_buffer, "no_trigger",
"\t modifier: %s", modifier);
weechat_printf_tags (trigger_buffer, "no_trigger",
"\t modifier_data: \"%s%s\"",
modifier_data,
weechat_color ("reset"));
trigger_buffer_display_hashtable ("extra_vars", extra_vars);
}
/* check conditions */
if (!trigger_callback_check_conditions (trigger, NULL, extra_vars))
goto end;
/* replace text with regex */
if (trigger->regex_count > 0)
{
string_modified = trigger_callback_replace_regex (trigger, string);
if (string_modified)
{
weechat_hashtable_set (extra_vars, "tg_string", string_modified);
if (strcmp (string, string_modified) == 0)
{
/* regex did not change the string, ignore it */
free (string_modified);
string_modified = NULL;
}
}
}
/* execute command */
trigger_callback_run_command (trigger, NULL, NULL, extra_vars);
end:
if (extra_vars)
weechat_hashtable_free (extra_vars);
trigger->hook_running = 0;
return string_modified;
}
/*
* Callback for a print hooked.
*/
int
trigger_callback_print_cb (void *data, struct t_gui_buffer *buffer,
time_t date, int tags_count, const char **tags,
int displayed, int highlight, const char *prefix,
const char *message)
{
struct t_trigger *trigger;
struct t_hashtable *pointers, *extra_vars;
const char *command, *localvar_type;
char *message2, *str_tags, *str_tags2, str_temp[128];
int i, rc, length, tag_notify_private;
struct tm *date_tmp;
/* get trigger pointer, return immediately if not found or trigger running */
trigger = (struct t_trigger *)data;
if (!trigger || trigger->hook_running)
return WEECHAT_RC_OK;
trigger->hook_count_cb++;
trigger->hook_running = 1;
pointers = NULL;
extra_vars = NULL;
rc = trigger_return_code[weechat_config_integer (trigger->options[TRIGGER_OPTION_RETURN_CODE])];
/* return if the buffer does not match buffers defined in the trigger */
if (trigger->hook_print_buffers
&& !weechat_buffer_match_list (buffer, trigger->hook_print_buffers))
goto end;
/*
* in a print, the only possible action is to execute a command;
* so if the command is empty, just exit without checking conditions
*/
command = weechat_config_string (trigger->options[TRIGGER_OPTION_COMMAND]);
if (!command || !command[0])
goto end;
/* create hashtables */
pointers = weechat_hashtable_new (32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_POINTER,
NULL,
NULL);
if (!pointers)
goto end;
extra_vars = weechat_hashtable_new (32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL,
NULL);
if (!extra_vars)
goto end;
/* add data in hashtable used for conditions/replace/command */
weechat_hashtable_set (pointers, "buffer", buffer);
date_tmp = localtime (&date);
if (date_tmp)
{
strftime (str_temp, sizeof (str_temp), "%Y-%m-%d %H:%M:%S", date_tmp);
weechat_hashtable_set (extra_vars, "tg_date", str_temp);
}
snprintf (str_temp, sizeof (str_temp), "%d", tags_count);
weechat_hashtable_set (extra_vars, "tg_tags_count", str_temp);
str_tags = weechat_string_build_with_split_string (tags, ",");
if (str_tags)
{
/* build string with tags and commas around: ",tag1,tag2,tag3," */
length = 1 + strlen (str_tags) + 1 + 1;
str_tags2 = malloc (length);
if (str_tags2)
{
snprintf (str_tags2, length, ",%s,", str_tags);
weechat_hashtable_set (extra_vars, "tg_tags", str_tags2);
free (str_tags2);
}
free (str_tags);
}
snprintf (str_temp, sizeof (str_temp), "%d", displayed);
weechat_hashtable_set (extra_vars, "tg_displayed", str_temp);
snprintf (str_temp, sizeof (str_temp), "%d", highlight);
weechat_hashtable_set (extra_vars, "tg_highlight", str_temp);
weechat_hashtable_set (extra_vars, "tg_prefix", prefix);
weechat_hashtable_set (extra_vars, "tg_message", message);
localvar_type = weechat_buffer_get_string (buffer, "localvar_type");
tag_notify_private = 0;
for (i = 0; i < tags_count; i++)
{
if (strcmp (tags[i], "no_trigger") == 0)
{
goto end;
}
else if (strcmp (tags[i], "notify_private") == 0)
{
tag_notify_private = 1;
}
}
snprintf (str_temp, sizeof (str_temp), "%d",
(tag_notify_private && localvar_type &&
(strcmp (localvar_type, "private") == 0)) ? 1 : 0);
weechat_hashtable_set (extra_vars, "tg_msg_pv", str_temp);
/* display debug info on trigger buffer */
if (!trigger_buffer && (weechat_trigger_plugin->debug >= 1))
trigger_buffer_open (0);
if (trigger_buffer)
{
weechat_printf_tags (trigger_buffer, "no_trigger",
"print\t%s%s",
weechat_color ("chat_channel"),
trigger->name);
weechat_printf_tags (trigger_buffer, "no_trigger",
"\t buffer: %s",
weechat_buffer_get_string (buffer, "full_name"));
trigger_buffer_display_hashtable ("pointers", pointers);
trigger_buffer_display_hashtable ("extra_vars", extra_vars);
}
/* check conditions */
if (!trigger_callback_check_conditions (trigger, pointers, extra_vars))
goto end;
/* replace text with regex */
if (trigger->regex_count > 0)
{
message2 = trigger_callback_replace_regex (trigger, message);
if (message2)
{
weechat_hashtable_set (extra_vars, "tg_message", message);
free (message2);
}
}
/* execute command */
trigger_callback_run_command (trigger, buffer, pointers, extra_vars);
end:
if (pointers)
weechat_hashtable_free (pointers);
if (extra_vars)
weechat_hashtable_free (extra_vars);
trigger->hook_running = 0;
return rc;
}
/*
* Initializes trigger callback.
*/
void
trigger_callback_init ()
{
trigger_callback_hashtable_options = weechat_hashtable_new (32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL,
NULL);
if (trigger_callback_hashtable_options)
{
weechat_hashtable_set (trigger_callback_hashtable_options,
"type", "condition");
}
}
/*
* Ends trigger callback.
*/
void
trigger_callback_end ()
{
if (trigger_callback_hashtable_options)
weechat_hashtable_free (trigger_callback_hashtable_options);
}
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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.
*
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __WEECHAT_TRIGGER_CALLBACK_H
#define __WEECHAT_TRIGGER_CALLBACK_H 1
extern int trigger_callback_signal_cb (void *data, const char *signal,
const char *type_data, void *signal_data);
extern int trigger_callback_hsignal_cb (void *data, const char *signal,
struct t_hashtable *hashtable);
extern char *trigger_callback_modifier_cb (void *data, const char *modifier,
const char *modifier_data,
const char *string);
extern int trigger_callback_print_cb (void *data, struct t_gui_buffer *buffer,
time_t date, int tags_count,
const char **tags, int displayed,
int highlight, const char *prefix,
const char *message);
extern void trigger_callback_init ();
extern void trigger_callback_end ();
#endif /* __WEECHAT_TRIGGER_CALLBACK_H */
+352
View File
@@ -0,0 +1,352 @@
/*
* trigger-command.c - trigger command
*
* Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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.
*
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include "../weechat-plugin.h"
#include "trigger.h"
#include "trigger-buffer.h"
#include "trigger-config.h"
/*
* Callback for command "/trigger": manage triggers.
*/
int
trigger_command_trigger (void *data, struct t_gui_buffer *buffer, int argc,
char **argv, char **argv_eol)
{
struct t_trigger *ptr_trigger;
const char *option;
int i, type, count, index_option, enabled;
/* make C compiler happy */
(void) data;
(void) buffer;
/* list all triggers */
if ((argc == 1)
|| ((argc == 2) && (weechat_strcasecmp (argv[1], "list") == 0)))
{
if (triggers)
{
weechat_printf_tags (NULL, "no_trigger", "");
weechat_printf_tags (NULL, "no_trigger", _("List of triggers:"));
for (ptr_trigger = triggers; ptr_trigger;
ptr_trigger = ptr_trigger->next_trigger)
{
weechat_printf_tags (NULL, "no_trigger",
" %s: %s, \"%s\" (%d hooks, %d/%d) %s",
ptr_trigger->name,
weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_HOOK]),
weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_ARGUMENTS]),
ptr_trigger->hooks_count,
ptr_trigger->hook_count_cb,
ptr_trigger->hook_count_cmd,
weechat_config_boolean (ptr_trigger->options[TRIGGER_OPTION_ENABLED]) ?
"" : _("(disabled)"));
option = weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_CONDITIONS]);
if (option && option[0])
{
weechat_printf_tags (NULL, "no_trigger",
" conditions: \"%s\"", option);
}
if (ptr_trigger->regex_count > 0)
{
weechat_printf_tags (NULL, "no_trigger",
" %d regex:",
ptr_trigger->regex_count);
for (i = 0; i < ptr_trigger->regex_count; i++)
{
weechat_printf_tags (NULL, "no_trigger",
" %d: %s%s %s-->%s %s",
i + 1,
weechat_color (weechat_config_string (trigger_config_color_regex)),
ptr_trigger->regex[i].str_regex,
weechat_color ("chat_delimiters"),
weechat_color (weechat_config_string (trigger_config_color_replace)),
ptr_trigger->regex[i].replace);
}
}
option = weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_COMMAND]);
if (option && option[0])
{
weechat_printf_tags (NULL, "no_trigger",
" command: \"%s\"", option);
}
}
}
else
{
weechat_printf_tags (NULL, "no_trigger", _("No trigger defined"));
}
return WEECHAT_RC_OK;
}
/* add a trigger */
if (weechat_strcasecmp (argv[1], "add") == 0)
{
if (argc < 4)
{
weechat_printf_tags (NULL, "no_trigger",
_("%sError: missing arguments for \"%s\" "
"command"),
weechat_prefix ("error"), "trigger");
return WEECHAT_RC_OK;
}
type = trigger_search_hook_type (argv[3]);
if (type < 0)
{
weechat_printf_tags (NULL, "no_trigger",
_("%s%s: invalid hook type \"%s\""),
weechat_prefix ("error"), TRIGGER_PLUGIN_NAME,
argv[3]);
return WEECHAT_RC_OK;
}
ptr_trigger = trigger_alloc (argv[2]);
if (!ptr_trigger)
{
weechat_printf_tags (NULL, "no_trigger",
_("%s%s: error creating trigger \"%s\""),
weechat_prefix ("error"), TRIGGER_PLUGIN_NAME,
argv[2]);
return WEECHAT_RC_OK;
}
if (trigger_new (argv[2], "on", argv[3],
(argc > 4) ? argv_eol[4] : "",
"", "", "", "ok"))
{
weechat_printf_tags (NULL, "no_trigger",
_("Trigger \"%s\" created"), argv[2]);
}
else
{
weechat_printf_tags (NULL, "no_trigger",
_("%sError: failed to create trigger \"%s\""),
weechat_prefix ("error"), argv[2]);
}
return WEECHAT_RC_OK;
}
/* set option in a trigger */
if (weechat_strcasecmp (argv[1], "set") == 0)
{
if (argc < 5)
{
weechat_printf_tags (NULL, "no_trigger",
_("%sError: missing arguments for \"%s\" "
"command"),
weechat_prefix ("error"), "trigger");
return WEECHAT_RC_OK;
}
ptr_trigger = trigger_search (argv[2]);
if (!ptr_trigger)
{
weechat_printf_tags (NULL, "no_trigger",
_("%sTrigger \"%s\" not found"),
weechat_prefix ("error"), argv[2]);
return WEECHAT_RC_OK;
}
if (weechat_strcasecmp (argv[3], "name") == 0)
{
trigger_rename (ptr_trigger, argv_eol[4]);
}
else
{
index_option = trigger_search_option (argv[3]);
if (index_option < 0)
{
weechat_printf_tags (NULL, "no_trigger",
_("%sTrigger option \"%s\" not found"),
weechat_prefix ("error"), argv[3]);
return WEECHAT_RC_OK;
}
weechat_config_option_set (ptr_trigger->options[index_option],
argv_eol[4], 1);
}
weechat_printf_tags (NULL, "no_trigger",
_("Trigger \"%s\" updated"), ptr_trigger->name);
return WEECHAT_RC_OK;
}
/* delete a trigger */
if (weechat_strcasecmp (argv[1], "del") == 0)
{
if (argc < 3)
{
weechat_printf_tags (NULL, "no_trigger",
_("%sError: missing arguments for \"%s\" "
"command"),
weechat_prefix ("error"), "trigger");
return WEECHAT_RC_OK;
}
if (weechat_strcasecmp (argv[2], "-all") == 0)
{
count = triggers_count;
trigger_free_all ();
if (count > 0)
weechat_printf_tags (NULL, "no_trigger",
_("%d triggers removed"), count);
}
else
{
for (i = 2; i < argc; i++)
{
ptr_trigger = trigger_search (argv[i]);
if (ptr_trigger)
{
trigger_free (ptr_trigger);
weechat_printf_tags (NULL, "no_trigger",
_("Trigger \"%s\" removed"), argv[i]);
}
else
{
weechat_printf_tags (NULL, "no_trigger",
_("%sTrigger \"%s\" not found"),
weechat_prefix ("error"), argv[i]);
}
}
}
return WEECHAT_RC_OK;
}
/* enable/disable/toggle a trigger */
if ((weechat_strcasecmp (argv[1], "enable") == 0)
|| (weechat_strcasecmp (argv[1], "disable") == 0)
|| (weechat_strcasecmp (argv[1], "toggle") == 0))
{
if (argc < 3)
{
weechat_printf_tags (NULL, "no_trigger",
_("%sError: missing arguments for \"%s\" "
"command"),
weechat_prefix ("error"), "trigger");
return WEECHAT_RC_OK;
}
ptr_trigger = trigger_search (argv[2]);
if (!ptr_trigger)
{
weechat_printf_tags (NULL, "no_trigger",
_("%sTrigger \"%s\" not found"),
weechat_prefix ("error"), argv[2]);
return WEECHAT_RC_OK;
}
if (weechat_strcasecmp (argv[1], "enable") == 0)
enabled = 1;
else if (weechat_strcasecmp (argv[1], "disable") == 0)
enabled = 0;
else
{
enabled = weechat_config_boolean (ptr_trigger->options[TRIGGER_OPTION_ENABLED]) ?
0 : 1;
}
weechat_config_option_set (ptr_trigger->options[TRIGGER_OPTION_ENABLED],
(enabled) ? "on" : "off", 1);
weechat_printf_tags (NULL, "no_trigger",
(enabled) ?
_("Trigger \"%s\" enabled") :
_("Trigger \"%s\" disabled"),
ptr_trigger->name);
return WEECHAT_RC_OK;
}
/* open the trigger monitor buffer */
if (weechat_strcasecmp (argv[1], "monitor") == 0)
{
trigger_buffer_open (1);
return WEECHAT_RC_OK;
}
return WEECHAT_RC_OK;
}
/*
* Hooks trigger commands.
*/
void
trigger_command_init ()
{
weechat_hook_command (
"trigger",
N_("manage triggers"),
N_("list"
" || add <name> <hook> [<arguments>]"
" || set <name> <option> <value>"
" || del <name>|-all [<name>...]"
" || enable|disable|toggle <name>"
" || monitor"),
N_(" add: add a trigger\n"
" name: name of trigger\n"
" hook: signal, hsignal, modifier, print, timer\n"
"arguments: arguments for the hook, depending on hook:\n"
" signal: name of signal\n"
" hsignal: name of hsignal\n"
" modifier: name of modifier\n"
" print: buffer, tags, message, strip_colors\n"
" timer: interval, align_second, max_calls\n"
" set: set an option in a trigger\n"
" option: name of option: name, hook, arguments, conditions, regex, "
"command, return_code\n"
" (for help on option, you can do /help "
"trigger.trigger.<name>.<option>)\n"
" value: new value for the option\n"
" del: delete a trigger\n"
" -all: delete all triggers\n"
" enable: enable a trigger\n"
" disable: disable a trigger\n"
" toggle: toggle a trigger\n"
" monitor: open the trigger monitor buffer\n"
"\n"
"When a trigger callback is called, following actions are performed, "
"in this order:\n"
" 1. if no regex/command is defined, exit\n"
" 2. check conditions; if false, exit\n"
" 3. replace text using regex (if defined in trigger)\n"
" 4. execute command (if defined in trigger)\n"
"Note: on steps 1 and 2, the exit is made with the return code "
"defined in trigger (or NULL for a modifier).\n"
"\n"
"Examples:\n"
" send alert (BEL) on highlight or private message:\n"
" /trigger add beep print\n"
" /trigger set beep conditions ${tg_highlight} || ${tg_msg_pv}\n"
" /trigger set beep command /print -stderr \\a\n"
" replace password with '*' in /oper command (in command line and "
"command history):\n"
" /trigger add oper modifier input_text_display;history_add\n"
" /trigger set oper regex ==^(/oper +\\S+ +)(.*)==\\1\\*2\n"
" add text attributes in *bold*, _underline_ and /italic/:\n"
" /trigger add effects modifier weechat_print\n"
" /trigger set effects regex "
"==\\*(\\S+)\\*==*${color:bold}\\1${color:-bold}*"
"==_(\\S+)_==_${color:underline}\\1${color:-underline}_"
"==/(\\S+)/==/${color:italic}\\1${color:-italic}/"),
"list"
" || add %(trigger_names) %(trigger_hooks)"
" || set %(trigger_names) %(trigger_options)|name %(trigger_option_value)"
" || del %(trigger_names)|-all %(trigger_names)|%*"
" || enable|disable|toggle %(trigger_names)"
" || monitor",
&trigger_command_trigger, NULL);
}
+25
View File
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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.
*
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __WEECHAT_TRIGGER_COMMAND_H
#define __WEECHAT_TRIGGER_COMMAND_H 1
extern void trigger_command_init ();
#endif /* __WEECHAT_TRIGGER_COMMAND_H */
+185
View File
@@ -0,0 +1,185 @@
/*
* trigger-completion.c - completion for trigger commands
*
* Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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.
*
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../weechat-plugin.h"
#include "trigger.h"
/*
* Adds triggers to completion list.
*/
int
trigger_completion_triggers_cb (void *data, const char *completion_item,
struct t_gui_buffer *buffer,
struct t_gui_completion *completion)
{
struct t_trigger *ptr_trigger;
/* make C compiler happy */
(void) data;
(void) completion_item;
(void) buffer;
for (ptr_trigger = triggers; ptr_trigger;
ptr_trigger = ptr_trigger->next_trigger)
{
weechat_hook_completion_list_add (completion, ptr_trigger->name,
0, WEECHAT_LIST_POS_SORT);
}
return WEECHAT_RC_OK;
}
/*
* Adds options for triggers to completion list.
*/
int
trigger_completion_options_cb (void *data, const char *completion_item,
struct t_gui_buffer *buffer,
struct t_gui_completion *completion)
{
int i;
/* make C compiler happy */
(void) data;
(void) completion_item;
(void) buffer;
for (i = 0; i < TRIGGER_NUM_OPTIONS; i++)
{
weechat_hook_completion_list_add (completion,
trigger_option_string[i],
0, WEECHAT_LIST_POS_SORT);
}
return WEECHAT_RC_OK;
}
/*
* Adds value of a trigger option to completion list.
*/
int
trigger_completion_option_value_cb (void *data, const char *completion_item,
struct t_gui_buffer *buffer,
struct t_gui_completion *completion)
{
const char *args;
char **argv;
int argc, index_option;
struct t_trigger *ptr_trigger;
/* make C compiler happy */
(void) data;
(void) completion_item;
(void) buffer;
args = weechat_hook_completion_get_string (completion, "args");
if (!args)
return WEECHAT_RC_OK;
argv = weechat_string_split (args, " ", 0, 0, &argc);
if (!argv)
return WEECHAT_RC_OK;
if (argc >= 3)
{
ptr_trigger = trigger_search (argv[1]);
if (ptr_trigger)
{
if (weechat_strcasecmp (argv[2], "name") == 0)
{
weechat_hook_completion_list_add (completion,
ptr_trigger->name,
0,
WEECHAT_LIST_POS_BEGINNING);
}
else
{
index_option = trigger_search_option (argv[2]);
if (index_option >= 0)
{
weechat_hook_completion_list_add (completion,
weechat_config_string (ptr_trigger->options[index_option]),
0,
WEECHAT_LIST_POS_BEGINNING);
}
}
}
}
weechat_string_free_split (argv);
return WEECHAT_RC_OK;
}
/*
* Adds hooks for triggers to completion list.
*/
int
trigger_completion_hooks_cb (void *data, const char *completion_item,
struct t_gui_buffer *buffer,
struct t_gui_completion *completion)
{
int i;
/* make C compiler happy */
(void) data;
(void) completion_item;
(void) buffer;
for (i = 0; i < TRIGGER_NUM_HOOK_TYPES; i++)
{
weechat_hook_completion_list_add (completion,
trigger_hook_type_string[i],
0, WEECHAT_LIST_POS_SORT);
}
return WEECHAT_RC_OK;
}
/*
* Hooks completions.
*/
void
trigger_completion_init ()
{
weechat_hook_completion ("trigger_names",
N_("triggers"),
&trigger_completion_triggers_cb, NULL);
weechat_hook_completion ("trigger_options",
N_("options for triggers"),
&trigger_completion_options_cb, NULL);
weechat_hook_completion ("trigger_option_value",
N_("value of a trigger option"),
&trigger_completion_option_value_cb, NULL);
weechat_hook_completion ("trigger_hooks",
N_("hooks for triggers"),
&trigger_completion_hooks_cb, NULL);
}
+25
View File
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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.
*
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __WEECHAT_TRIGGER_COMPLETION_H
#define __WEECHAT_TRIGGER_COMPLETION_H 1
extern void trigger_completion_init ();
#endif /* __WEECHAT_TRIGGER_COMPLETION_H */
+484
View File
@@ -0,0 +1,484 @@
/*
* trigger-config.c - trigger configuration options (file trigger.conf)
*
* Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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.
*
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../weechat-plugin.h"
#include "trigger.h"
#include "trigger-config.h"
struct t_config_file *trigger_config_file = NULL;
struct t_config_section *trigger_config_section_trigger = NULL;
/* trigger config, look section */
struct t_config_option *trigger_config_look_test;
/* trigger config, color section */
struct t_config_option *trigger_config_color_regex;
struct t_config_option *trigger_config_color_replace;
/*
* Callback called when trigger option "enabled" is changed.
*/
void
trigger_config_change_enabled (void *data, struct t_config_option *option)
{
struct t_trigger *ptr_trigger;
/* make C compiler happy */
(void) data;
ptr_trigger = trigger_search_with_option (option);
if (!ptr_trigger)
return;
if (weechat_config_boolean (option))
trigger_hook (ptr_trigger);
else
trigger_unhook (ptr_trigger);
}
/*
* Callback called when trigger option "arguments" is changed.
*/
void
trigger_config_change_arguments (void *data, struct t_config_option *option)
{
struct t_trigger *ptr_trigger;
/* make C compiler happy */
(void) data;
ptr_trigger = trigger_search_with_option (option);
if (!ptr_trigger)
return;
trigger_hook (ptr_trigger);
}
/*
* Callback called when trigger option "regex" is changed.
*/
void
trigger_config_change_regex (void *data, struct t_config_option *option)
{
struct t_trigger *ptr_trigger;
/* make C compiler happy */
(void) data;
ptr_trigger = trigger_search_with_option (option);
if (!ptr_trigger)
return;
trigger_set_regex (ptr_trigger);
}
/*
* Creates an option for a trigger.
*
* Returns pointer to new option, NULL if error.
*/
struct t_config_option *
trigger_config_create_option (const char *trigger_name, int index_option,
const char *value)
{
struct t_config_option *ptr_option;
int length;
char *option_name;
ptr_option = NULL;
length = strlen (trigger_name) + 1 +
strlen (trigger_option_string[index_option]) + 1;
option_name = malloc (length);
if (!option_name)
return NULL;
snprintf (option_name, length, "%s.%s",
trigger_name, trigger_option_string[index_option]);
switch (index_option)
{
case TRIGGER_OPTION_ENABLED:
ptr_option = weechat_config_new_option (
trigger_config_file, trigger_config_section_trigger,
option_name, "boolean",
N_("true if trigger is enabled, otherwise false"),
NULL, 0, 0, value, NULL, 0,
NULL, NULL, &trigger_config_change_enabled, NULL, NULL, NULL);
break;
case TRIGGER_OPTION_HOOK:
ptr_option = weechat_config_new_option (
trigger_config_file, trigger_config_section_trigger,
option_name, "integer",
N_("type of hook used"),
"signal|hsignal|modifier|print|timer", 0, 0, value, NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL);
break;
case TRIGGER_OPTION_ARGUMENTS:
ptr_option = weechat_config_new_option (
trigger_config_file, trigger_config_section_trigger,
option_name, "string",
N_("arguments for the hook (depend on the hook type); for "
"signal/hsignal/modifier: name, for print: "
"buffer;tags;strip_colors;message, for timer: "
"interval;align_second;max_calls"),
NULL, 0, 0, value, NULL, 0,
NULL, NULL, &trigger_config_change_arguments, NULL, NULL, NULL);
break;
case TRIGGER_OPTION_CONDITIONS:
ptr_option = weechat_config_new_option (
trigger_config_file, trigger_config_section_trigger,
option_name, "string",
N_("condition(s) for running the command (it is checked in "
"hook callback)"),
NULL, 0, 0, value, NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL);
break;
case TRIGGER_OPTION_REGEX:
ptr_option = weechat_config_new_option (
trigger_config_file, trigger_config_section_trigger,
option_name, "string",
N_("replace text with a POSIX extended regular expression"),
NULL, 0, 0, value, NULL, 0,
NULL, NULL, &trigger_config_change_regex, NULL, NULL, NULL);
break;
case TRIGGER_OPTION_COMMAND:
ptr_option = weechat_config_new_option (
trigger_config_file, trigger_config_section_trigger,
option_name, "string",
N_("command run if conditions are OK"),
NULL, 0, 0, value, NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL);
break;
case TRIGGER_OPTION_RETURN_CODE:
ptr_option = weechat_config_new_option (
trigger_config_file, trigger_config_section_trigger,
option_name, "integer",
N_("return code for hook callback"),
"ok|ok_eat|error", 0, 0, value, NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL);
break;
case TRIGGER_NUM_OPTIONS:
break;
}
free (option_name);
return ptr_option;
}
/*
* Creates option for a temporary trigger (when reading configuration file).
*/
void
trigger_config_create_option_temp (struct t_trigger *temp_trigger,
int index_option, const char *value)
{
struct t_config_option *new_option;
new_option = trigger_config_create_option (temp_trigger->name,
index_option, value);
if (new_option
&& (index_option >= 0) && (index_option < TRIGGER_NUM_OPTIONS))
{
temp_trigger->options[index_option] = new_option;
}
}
/*
* Uses temporary triggers (created by reading configuration file).
*/
void
trigger_config_use_temp_triggers ()
{
struct t_trigger *ptr_temp_trigger, *next_temp_trigger;
int i, num_options_ok;
for (ptr_temp_trigger = triggers_temp; ptr_temp_trigger;
ptr_temp_trigger = ptr_temp_trigger->next_trigger)
{
num_options_ok = 0;
for (i = 0; i < TRIGGER_NUM_OPTIONS; i++)
{
if (!ptr_temp_trigger->options[i])
{
ptr_temp_trigger->options[i] =
trigger_config_create_option (ptr_temp_trigger->name,
i,
trigger_option_default[i]);
}
if (ptr_temp_trigger->options[i])
num_options_ok++;
}
if (num_options_ok == TRIGGER_NUM_OPTIONS)
{
trigger_new_with_options (ptr_temp_trigger->name,
ptr_temp_trigger->options);
}
else
{
for (i = 0; i < TRIGGER_NUM_OPTIONS; i++)
{
if (ptr_temp_trigger->options[i])
{
weechat_config_option_free (ptr_temp_trigger->options[i]);
ptr_temp_trigger->options[i] = NULL;
}
}
}
}
/* free all temporary triggers */
while (triggers_temp)
{
next_temp_trigger = triggers_temp->next_trigger;
if (triggers_temp->name)
free (triggers_temp->name);
free (triggers_temp);
triggers_temp = next_temp_trigger;
}
last_trigger_temp = NULL;
}
/*
* Reads a trigger option in trigger configuration file.
*/
int
trigger_config_trigger_read_cb (void *data, struct t_config_file *config_file,
struct t_config_section *section,
const char *option_name, const char *value)
{
char *pos_option, *trigger_name;
struct t_trigger *ptr_temp_trigger;
int index_option;
/* make C compiler happy */
(void) data;
(void) config_file;
(void) section;
if (!option_name)
return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE;
pos_option = strchr (option_name, '.');
if (!pos_option)
return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE;
trigger_name = weechat_strndup (option_name, pos_option - option_name);
if (!trigger_name)
return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE;
pos_option++;
/* search temporary trigger */
for (ptr_temp_trigger = triggers_temp; ptr_temp_trigger;
ptr_temp_trigger = ptr_temp_trigger->next_trigger)
{
if (strcmp (ptr_temp_trigger->name, trigger_name) == 0)
break;
}
if (!ptr_temp_trigger)
{
/* create new temporary trigger */
ptr_temp_trigger = trigger_alloc (trigger_name);
if (ptr_temp_trigger)
trigger_add (ptr_temp_trigger, &triggers_temp, &last_trigger_temp);
}
if (ptr_temp_trigger)
{
index_option = trigger_search_option (pos_option);
if (index_option >= 0)
{
trigger_config_create_option_temp (ptr_temp_trigger, index_option,
value);
}
else
{
weechat_printf (NULL,
_("%sWarning: unknown option for section \"%s\": "
"%s (value: \"%s\")"),
weechat_prefix ("error"),
TRIGGER_CONFIG_SECTION_TRIGGER,
option_name, value);
}
}
free (trigger_name);
return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE;
}
/*
* Reloads trigger configuration file.
*/
int
trigger_config_reload_cb (void *data, struct t_config_file *config_file)
{
int rc;
/* make C compiler happy */
(void) data;
trigger_free_all ();
rc = weechat_config_reload (config_file);
trigger_config_use_temp_triggers ();
return rc;
}
/*
* Initializes trigger configuration file.
*
* Returns:
* 1: OK
* 0: error
*/
int
trigger_config_init ()
{
struct t_config_section *ptr_section;
trigger_config_file = weechat_config_new (TRIGGER_CONFIG_NAME,
&trigger_config_reload_cb, NULL);
if (!trigger_config_file)
return 0;
/* look */
ptr_section = weechat_config_new_section (trigger_config_file, "look",
0, 0,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL);
if (!ptr_section)
{
weechat_config_free (trigger_config_file);
return 0;
}
trigger_config_look_test = weechat_config_new_option (
trigger_config_file, ptr_section,
"test", "boolean",
"",
NULL, 0, 0, "on", NULL, 0, NULL, NULL,
NULL, NULL, NULL, NULL);
/* color */
ptr_section = weechat_config_new_section (trigger_config_file, "color",
0, 0,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL);
if (!ptr_section)
{
weechat_config_free (trigger_config_file);
return 0;
}
trigger_config_color_regex = weechat_config_new_option (
trigger_config_file, ptr_section,
"regex", "color",
N_("text color for regular expressions"),
NULL, 0, 0, "white", NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL);
trigger_config_color_replace = weechat_config_new_option (
trigger_config_file, ptr_section,
"replace", "color",
N_("text color for replacement text (for regular expressions)"),
NULL, 0, 0, "cyan", NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL);
/* trigger */
ptr_section = weechat_config_new_section (trigger_config_file,
TRIGGER_CONFIG_SECTION_TRIGGER,
0, 0,
&trigger_config_trigger_read_cb, NULL,
NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL);
if (!ptr_section)
{
weechat_config_free (trigger_config_file);
return 0;
}
trigger_config_section_trigger = ptr_section;
return 1;
}
/*
* Reads trigger configuration file.
*/
int
trigger_config_read ()
{
int rc;
rc = weechat_config_read (trigger_config_file);
trigger_config_use_temp_triggers ();
return rc;
}
/*
* Writes trigger configuration file.
*/
int
trigger_config_write ()
{
return weechat_config_write (trigger_config_file);
}
/*
* Frees trigger configuration.
*/
void
trigger_config_free ()
{
weechat_config_free (trigger_config_file);
}
+40
View File
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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.
*
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __WEECHAT_TRIGGER_CONFIG_H
#define __WEECHAT_TRIGGER_CONFIG_H 1
#define TRIGGER_CONFIG_NAME "trigger"
#define TRIGGER_CONFIG_SECTION_TRIGGER "trigger"
extern struct t_config_file *trigger_config_file;
extern struct t_config_section *trigger_config_section_trigger;
extern struct t_config_option *trigger_config_color_regex;
extern struct t_config_option *trigger_config_color_replace;
extern struct t_config_option *trigger_config_create_option (const char *trigger_name,
int index_option,
const char *value);
extern int trigger_config_init ();
extern int trigger_config_read ();
extern int trigger_config_write ();
extern void trigger_config_free ();
#endif /* __WEECHAT_TRIGGER_CONFIG_H */
+894
View File
@@ -0,0 +1,894 @@
/*
* trigger.c - trigger plugin for WeeChat
*
* Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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.
*
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <regex.h>
#include "../weechat-plugin.h"
#include "trigger.h"
#include "trigger-buffer.h"
#include "trigger-callback.h"
#include "trigger-command.h"
#include "trigger-completion.h"
#include "trigger-config.h"
WEECHAT_PLUGIN_NAME(TRIGGER_PLUGIN_NAME);
WEECHAT_PLUGIN_DESCRIPTION(N_("Run actions on events triggered by WeeChat/plugins"));
WEECHAT_PLUGIN_AUTHOR("Sébastien Helleu <flashcode@flashtux.org>");
WEECHAT_PLUGIN_VERSION(WEECHAT_VERSION);
WEECHAT_PLUGIN_LICENSE(WEECHAT_LICENSE);
struct t_weechat_plugin *weechat_trigger_plugin = NULL;
char *trigger_option_string[TRIGGER_NUM_OPTIONS] =
{ "enabled", "hook", "arguments", "conditions", "regex", "command",
"return_code" };
char *trigger_option_default[TRIGGER_NUM_OPTIONS] =
{ "on", "signal", "", "", "", "", "ok" };
char *trigger_hook_type_string[TRIGGER_NUM_HOOK_TYPES] =
{ "signal", "hsignal", "modifier", "print", "timer" };
char *trigger_return_code_string[TRIGGER_NUM_RETURN_CODES] =
{ "ok", "ok_eat", "error" };
int trigger_return_code[TRIGGER_NUM_RETURN_CODES] =
{ WEECHAT_RC_OK, WEECHAT_RC_OK_EAT, WEECHAT_RC_ERROR };
struct t_trigger *triggers = NULL; /* first trigger */
struct t_trigger *last_trigger = NULL; /* last trigger */
int triggers_count = 0; /* number of triggers */
struct t_trigger *triggers_temp = NULL; /* first temporary trigger */
struct t_trigger *last_trigger_temp = NULL; /* last temporary trigger */
/*
* Searches for a trigger option name.
*
* Returns index of option in enum t_trigger_option, -1 if not found.
*/
int
trigger_search_option (const char *option_name)
{
int i;
if (!option_name)
return -1;
for (i = 0; i < TRIGGER_NUM_OPTIONS; i++)
{
if (weechat_strcasecmp (trigger_option_string[i], option_name) == 0)
return i;
}
/* trigger option not found */
return -1;
}
/*
* Searches for trigger hook type.
*
* Returns index of hook type in enum t_trigger_hook_type, -1 if not found.
*/
int
trigger_search_hook_type (const char *type)
{
int i;
for (i = 0; i < TRIGGER_NUM_HOOK_TYPES; i++)
{
if (weechat_strcasecmp (trigger_hook_type_string[i], type) == 0)
return i;
}
/* hook type not found */
return -1;
}
/*
* Searches for trigger return code.
*
* Returns index of return code in enum t_trigger_return_code, -1 if not found.
*/
int
trigger_search_return_code (const char *return_code)
{
int i;
for (i = 0; i < TRIGGER_NUM_RETURN_CODES; i++)
{
if (weechat_strcasecmp (trigger_return_code_string[i], return_code) == 0)
return i;
}
/* return code not found */
return -1;
}
/*
* Searches for a trigger by name.
*
* Returns pointer to trigger found, NULL if not found.
*/
struct t_trigger *
trigger_search (const char *name)
{
struct t_trigger *ptr_trigger;
if (!name || !name[0])
return NULL;
for (ptr_trigger = triggers; ptr_trigger;
ptr_trigger = ptr_trigger->next_trigger)
{
if (strcmp (ptr_trigger->name, name) == 0)
return ptr_trigger;
}
/* trigger not found */
return NULL;
}
/*
* Searches for a trigger with a pointer to a trigger option.
*
* Returns pointer to trigger found, NULL if not found.
*/
struct t_trigger *
trigger_search_with_option (struct t_config_option *option)
{
const char *ptr_name;
char *pos_option;
struct t_trigger *ptr_trigger;
ptr_name = weechat_hdata_string (weechat_hdata_get ("config_option"),
option, "name");
if (!ptr_name)
return NULL;
pos_option = strchr (ptr_name, '.');
if (!pos_option)
return NULL;
for (ptr_trigger = triggers; ptr_trigger;
ptr_trigger = ptr_trigger->next_trigger)
{
if (strncmp (ptr_trigger->name, ptr_name, pos_option - ptr_name) == 0)
break;
}
return ptr_trigger;
}
/*
* Frees all the regex in a trigger.
*/
void
trigger_free_regex (struct t_trigger *trigger)
{
int i;
if (trigger->regex_count > 0)
{
for (i = 0; i < trigger->regex_count; i++)
{
if (trigger->regex[i].str_regex)
free (trigger->regex[i].str_regex);
if (trigger->regex[i].regex)
{
regfree (trigger->regex[i].regex);
free (trigger->regex[i].regex);
}
if (trigger->regex[i].replace)
free (trigger->regex[i].replace);
if (trigger->regex[i].replace_eval)
free (trigger->regex[i].replace_eval);
}
free (trigger->regex);
trigger->regex = NULL;
trigger->regex_count = 0;
}
}
/*
* Sets the regex and replacement text in a trigger.
*/
void
trigger_set_regex (struct t_trigger *trigger)
{
const char *option_regex, *pos, *pos2;
char *delimiter;
int i, length_delimiter, regex_count;
delimiter = NULL;
/* remove all regex in the trigger */
trigger_free_regex (trigger);
/* get regex option in trigger */
option_regex = weechat_config_string (trigger->options[TRIGGER_OPTION_REGEX]);
if (!option_regex || !option_regex[0])
goto end;
/* min 3 chars, for example: "/a/" */
if (strlen (option_regex) < 3)
goto format_error;
/* search the delimiter (which can be more than one char) */
pos = weechat_utf8_next_char (option_regex);
while (pos[0] && weechat_utf8_charcmp (option_regex, pos) == 0)
{
pos = weechat_utf8_next_char (pos);
}
if (!pos[0])
goto format_error;
delimiter = weechat_strndup (option_regex, pos - option_regex);
if (!delimiter)
goto memory_error;
if (strcmp (delimiter, "\\") == 0)
goto format_error;
length_delimiter = strlen (delimiter);
/* count the number of regex in the option */
regex_count = 0;
pos = option_regex;
while (pos && pos[0])
{
/*
* if option "regex" ends with a delimiter, just ignore it
* and exit the loop
*/
pos += length_delimiter;
if (!pos[0])
break;
/* search the start of replacement string */
pos = strstr (pos + length_delimiter, delimiter);
if (!pos)
goto format_error;
regex_count++;
/* search the start of next regex */
pos = strstr (pos + length_delimiter, delimiter);
}
/* at least one regex is needed */
if (regex_count == 0)
goto format_error;
/* allocate with array of regex/replacement */
trigger->regex = malloc (regex_count * sizeof (trigger->regex[0]));
if (!trigger->regex)
goto memory_error;
/* initialize regex */
for (i = 0; i < trigger->regex_count; i++)
{
trigger->regex[i].str_regex = NULL;
trigger->regex[i].regex = NULL;
trigger->regex[i].replace = NULL;
trigger->regex[i].replace_eval = NULL;
}
trigger->regex_count = regex_count;
/* allocate regex and replacement */
i = 0;
pos = option_regex;
while (pos && pos[0])
{
pos += length_delimiter;
if (!pos[0])
break;
pos2 = strstr (pos + length_delimiter, delimiter);
if (!pos)
break;
trigger->regex[i].str_regex = weechat_strndup (pos, pos2 - pos);
if (!trigger->regex[i].str_regex)
goto memory_error;
trigger->regex[i].regex = malloc (sizeof (*trigger->regex[i].regex));
if (!trigger->regex[i].regex)
goto memory_error;
if (weechat_string_regcomp (trigger->regex[i].regex,
trigger->regex[i].str_regex,
REG_EXTENDED | REG_ICASE) != 0)
{
weechat_printf (NULL,
_("%s%s: error compiling regular expression \"%s\""),
weechat_prefix ("error"), TRIGGER_PLUGIN_NAME,
trigger->regex[i].str_regex);
free (trigger->regex[i].regex);
trigger->regex[i].regex = NULL;
goto end;
}
pos = pos2 + length_delimiter;
pos2 = strstr (pos + length_delimiter, delimiter);
trigger->regex[i].replace = (pos2) ?
weechat_strndup (pos, pos2 - pos) : strdup (pos);
if (!trigger->regex[i].replace)
goto memory_error;
trigger->regex[i].replace_eval =
weechat_string_eval_expression (trigger->regex[i].replace,
NULL, NULL, NULL);
pos = pos2;
i++;
}
goto end;
format_error:
weechat_printf (NULL,
_("%s%s: invalid value for option \"replace\", format "
"is: \"/regex/replace\" (the char '/' can be "
"replaced by one or more identical chars, except '\\' "
"which is used for matching groups)"),
weechat_prefix ("error"), TRIGGER_PLUGIN_NAME);
trigger_free_regex (trigger);
goto end;
memory_error:
weechat_printf (NULL,
_("%s%s: not enough memory"),
weechat_prefix ("error"), TRIGGER_PLUGIN_NAME);
trigger_free_regex (trigger);
goto end;
end:
if (delimiter)
free (delimiter);
}
/*
* Unhooks things hooked in a trigger.
*/
void
trigger_unhook (struct t_trigger *trigger)
{
int i;
if (trigger->hooks)
{
for (i = 0; i < trigger->hooks_count; i++)
{
weechat_unhook (trigger->hooks[i]);
}
free (trigger->hooks);
trigger->hooks = NULL;
trigger->hooks_count = 0;
}
trigger->hook_count_cb = 0;
trigger->hook_count_cmd = 0;
if (trigger->hook_print_buffers)
{
free (trigger->hook_print_buffers);
trigger->hook_print_buffers = NULL;
}
}
/*
* Creates hook(s) in a trigger.
*/
void
trigger_hook (struct t_trigger *trigger)
{
char **argv, **argv_eol, *tags, *message;
int i, argc, strip_colors;
trigger_unhook (trigger);
argv = weechat_string_split (weechat_config_string (trigger->options[TRIGGER_OPTION_ARGUMENTS]),
";", 0, 0, &argc);
argv_eol = weechat_string_split (weechat_config_string (trigger->options[TRIGGER_OPTION_ARGUMENTS]),
";", 1, 0, NULL);
switch (weechat_config_integer (trigger->options[TRIGGER_OPTION_HOOK]))
{
case TRIGGER_HOOK_SIGNAL:
if (argv && (argc >= 1))
{
trigger->hooks = malloc (argc * sizeof (trigger->hooks[0]));
if (trigger->hooks)
{
trigger->hooks_count = argc;
for (i = 0; i < argc; i++)
{
trigger->hooks[i] = weechat_hook_signal (argv[i],
&trigger_callback_signal_cb,
trigger);
}
}
}
break;
case TRIGGER_HOOK_HSIGNAL:
if (argv && (argc >= 1))
{
trigger->hooks = malloc (argc * sizeof (trigger->hooks[0]));
if (trigger->hooks)
{
trigger->hooks_count = argc;
for (i = 0; i < argc; i++)
{
trigger->hooks[i] = weechat_hook_hsignal (argv[i],
&trigger_callback_hsignal_cb,
trigger);
}
}
}
break;
case TRIGGER_HOOK_MODIFIER:
if (argv && (argc >= 1))
{
trigger->hooks = malloc (argc * sizeof (trigger->hooks[0]));
if (trigger->hooks)
{
trigger->hooks_count = argc;
for (i = 0; i < argc; i++)
{
trigger->hooks[i] = weechat_hook_modifier (argv[i],
&trigger_callback_modifier_cb,
trigger);
}
}
}
break;
case TRIGGER_HOOK_PRINT:
tags = NULL;
message = NULL;
strip_colors = 0;
if (argv && (argc >= 1))
{
if (strcmp (argv[0], "*") != 0)
trigger->hook_print_buffers = strdup (argv[0]);
if ((argc >= 2) && (strcmp (argv[1], "*") != 0))
tags = argv[1];
if ((argc >= 3) && (strcmp (argv[2], "*") != 0))
message = argv[2];
if (argc >= 4)
strip_colors = (strcmp (argv[3], "0") != 0) ? 1 : 0;
}
trigger->hooks = malloc (1 * sizeof (trigger->hooks[0]));
if (trigger->hooks)
{
trigger->hooks_count = 1;
trigger->hooks[0] = weechat_hook_print (NULL, tags, message,
strip_colors,
&trigger_callback_print_cb,
trigger);
}
break;
case TRIGGER_HOOK_TIMER:
if (argv && (argc >= 1))
{
}
break;
}
if (!trigger->hooks)
{
weechat_printf (NULL,
_("%sError: unable to create hook for trigger \"%s\" "
"(bad arguments)"),
weechat_prefix ("error"), trigger->name);
}
if (argv)
weechat_string_free_split (argv);
if (argv_eol)
weechat_string_free_split (argv_eol);
}
/*
* Allocates and initializes new trigger structure.
*
* Returns pointer to new trigger, NULL if error.
*/
struct t_trigger *
trigger_alloc (const char *name)
{
struct t_trigger *new_trigger;
int i;
if (trigger_search (name))
return NULL;
new_trigger = malloc (sizeof (*new_trigger));
if (!new_trigger)
return NULL;
new_trigger->name = strdup (name);
for (i = 0; i < TRIGGER_NUM_OPTIONS; i++)
{
new_trigger->options[i] = NULL;
}
new_trigger->regex_count = 0;
new_trigger->regex = NULL;
new_trigger->hooks_count = 0;
new_trigger->hooks = NULL;
new_trigger->hook_count_cb = 0;
new_trigger->hook_count_cmd = 0;
new_trigger->hook_running = 0;
new_trigger->hook_print_buffers = NULL;
new_trigger->prev_trigger = NULL;
new_trigger->next_trigger = NULL;
return new_trigger;
}
/*
* Adds trigger to the end of a linked list.
*/
void
trigger_add (struct t_trigger *trigger,
struct t_trigger **triggers, struct t_trigger **last_trigger)
{
trigger->prev_trigger = *last_trigger;
trigger->next_trigger = NULL;
if (!*triggers)
*triggers = trigger;
else
(*last_trigger)->next_trigger = trigger;
*last_trigger = trigger;
triggers_count++;
}
/*
* Creates a new trigger with options.
*
* Returns pointer to new trigger, NULL if error.
*/
struct t_trigger *
trigger_new_with_options (const char *name, struct t_config_option **options)
{
struct t_trigger *new_trigger;
int i;
new_trigger = trigger_alloc (name);
if (!new_trigger)
return NULL;
for (i = 0; i < TRIGGER_NUM_OPTIONS; i++)
{
new_trigger->options[i] = options[i];
}
trigger_add (new_trigger, &triggers, &last_trigger);
trigger_set_regex (new_trigger);
if (weechat_config_boolean (new_trigger->options[TRIGGER_OPTION_ENABLED]))
trigger_hook (new_trigger);
return new_trigger;
}
/*
* Creates a new trigger.
*
* Returns pointer to new trigger, NULL if error.
*/
struct t_trigger *
trigger_new (const char *name, const char *enabled, const char *hook,
const char *arguments, const char *conditions, const char *regex,
const char *command, const char *return_code)
{
struct t_config_option *option[TRIGGER_NUM_OPTIONS];
const char *value[TRIGGER_NUM_OPTIONS];
struct t_trigger *new_trigger;
int i;
/* it's not possible to create 2 triggers with same name */
if (trigger_search (name))
return NULL;
/* look for type */
if (trigger_search_hook_type (hook) < 0)
return NULL;
/* look for return code */
if (trigger_search_return_code (return_code) < 0)
return NULL;
value[TRIGGER_OPTION_ENABLED] = enabled;
value[TRIGGER_OPTION_HOOK] = hook;
value[TRIGGER_OPTION_ARGUMENTS] = arguments;
value[TRIGGER_OPTION_CONDITIONS] = conditions;
value[TRIGGER_OPTION_REGEX] = regex;
value[TRIGGER_OPTION_COMMAND] = command;
value[TRIGGER_OPTION_RETURN_CODE] = return_code;
for (i = 0; i < TRIGGER_NUM_OPTIONS; i++)
{
option[i] = trigger_config_create_option (name, i, value[i]);
}
new_trigger = trigger_new_with_options (name, option);
if (!new_trigger)
{
for (i = 0; i < TRIGGER_NUM_OPTIONS; i++)
{
weechat_config_option_free (option[i]);
}
}
return new_trigger;
}
/*
* Renames a trigger.
*/
void
trigger_rename (struct t_trigger *trigger, const char *name)
{
int length, i;
char *option_name;
if (!name || !name[0])
return;
length = strlen (name) + 64;
option_name = malloc (length);
if (!option_name)
return;
for (i = 0; i < TRIGGER_NUM_OPTIONS; i++)
{
if (trigger->options[i])
{
snprintf (option_name, length,
"%s.%s",
name,
trigger_option_string[i]);
weechat_config_option_rename (trigger->options[i], option_name);
}
}
if (trigger->name)
free (trigger->name);
trigger->name = strdup (name);
free (option_name);
}
/*
* Deletes a trigger.
*/
void
trigger_free (struct t_trigger *trigger)
{
int i;
if (!trigger)
return;
/* remove trigger from triggers list */
if (trigger->prev_trigger)
(trigger->prev_trigger)->next_trigger = trigger->next_trigger;
if (trigger->next_trigger)
(trigger->next_trigger)->prev_trigger = trigger->prev_trigger;
if (triggers == trigger)
triggers = trigger->next_trigger;
if (last_trigger == trigger)
last_trigger = trigger->prev_trigger;
/* free data */
trigger_unhook (trigger);
trigger_free_regex (trigger);
if (trigger->name)
free (trigger->name);
for (i = 0; i < TRIGGER_NUM_OPTIONS; i++)
{
if (trigger->options[i])
weechat_config_option_free (trigger->options[i]);
}
free (trigger);
triggers_count--;
}
/*
* Deletes all triggers.
*/
void
trigger_free_all ()
{
while (triggers)
{
trigger_free (triggers);
}
}
/*
* Prints trigger infos in WeeChat log file (usually for crash dump).
*/
void
trigger_print_log ()
{
struct t_trigger *ptr_trigger;
int i;
for (ptr_trigger = triggers; ptr_trigger;
ptr_trigger = ptr_trigger->next_trigger)
{
weechat_log_printf ("");
weechat_log_printf ("[trigger (addr:0x%lx)]", ptr_trigger);
weechat_log_printf (" name. . . . . . . . . . : '%s'", ptr_trigger->name);
weechat_log_printf (" enabled . . . . . . . . : %d",
weechat_config_integer (ptr_trigger->options[TRIGGER_OPTION_ENABLED]));
weechat_log_printf (" hook . . . . . . . . . : %d ('%s')",
weechat_config_integer (ptr_trigger->options[TRIGGER_OPTION_HOOK]),
trigger_hook_type_string[weechat_config_integer (ptr_trigger->options[TRIGGER_OPTION_HOOK])]);
weechat_log_printf (" arguments . . . . . . . : '%s'",
weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_ARGUMENTS]));
weechat_log_printf (" conditions. . . . . . . : '%s'",
weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_CONDITIONS]));
weechat_log_printf (" regex . . . . . . . . . : '%s'",
weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_REGEX]));
weechat_log_printf (" command . . . . . . . . : '%s'",
weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_COMMAND]));
weechat_log_printf (" return_code . . . . . . : %d ('%s')",
weechat_config_integer (ptr_trigger->options[TRIGGER_OPTION_RETURN_CODE]),
trigger_return_code_string[weechat_config_integer (ptr_trigger->options[TRIGGER_OPTION_RETURN_CODE])]);
weechat_log_printf (" regex_count . . . . . . : %d", ptr_trigger->regex_count);
weechat_log_printf (" regex . . . . . . . . . : 0x%lx", ptr_trigger->regex);
for (i = 0; i < ptr_trigger->regex_count; i++)
{
weechat_log_printf (" regex[%03d].regex. . . : 0x%lx",
i, ptr_trigger->regex[i].regex);
weechat_log_printf (" regex[%03d].replace. . : '%s'",
i, ptr_trigger->regex[i].replace);
}
weechat_log_printf (" hooks_count . . . . . . : %d", ptr_trigger->hooks_count);
weechat_log_printf (" hooks . . . . . . . . . : 0x%lx", ptr_trigger->hooks);
for (i = 0; i < ptr_trigger->hooks_count; i++)
{
weechat_log_printf (" hooks[%03d]. . . . . . : 0x%lx",
i, ptr_trigger->hooks[i]);
}
weechat_log_printf (" hook_count_cb . . . . . : %lu", ptr_trigger->hook_count_cb);
weechat_log_printf (" hook_count_cmd. . . . . : %lu", ptr_trigger->hook_count_cmd);
weechat_log_printf (" hook_running. . . . . . : %d", ptr_trigger->hook_running);
weechat_log_printf (" hook_print_buffers. . . : '%s'", ptr_trigger->hook_print_buffers);
weechat_log_printf (" prev_trigger. . . . . . : 0x%lx", ptr_trigger->prev_trigger);
weechat_log_printf (" next_trigger. . . . . . : 0x%lx", ptr_trigger->next_trigger);
}
}
/*
* Callback for signal "debug_dump".
*/
int
trigger_debug_dump_cb (void *data, const char *signal, const char *type_data,
void *signal_data)
{
/* make C compiler happy */
(void) data;
(void) signal;
(void) type_data;
if (!signal_data
|| (weechat_strcasecmp ((char *)signal_data, TRIGGER_PLUGIN_NAME) == 0))
{
weechat_log_printf ("");
weechat_log_printf ("***** \"%s\" plugin dump *****",
weechat_plugin->name);
trigger_print_log ();
weechat_log_printf ("");
weechat_log_printf ("***** End of \"%s\" plugin dump *****",
weechat_plugin->name);
}
return WEECHAT_RC_OK;
}
/*
* Initializes trigger plugin.
*/
int
weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[])
{
int i, upgrading;
/* make C compiler happy */
(void) argc;
(void) argv;
weechat_plugin = plugin;
trigger_callback_init ();
trigger_command_init ();
if (!trigger_config_init ())
return WEECHAT_RC_ERROR;
trigger_config_read ();
/* hook some signals */
weechat_hook_signal ("debug_dump", &trigger_debug_dump_cb, NULL);
/* hook completions */
trigger_completion_init ();
/* look at arguments */
upgrading = 0;
for (i = 0; i < argc; i++)
{
if (weechat_strcasecmp (argv[i], "--upgrade") == 0)
{
upgrading = 1;
}
}
if (upgrading)
trigger_buffer_set_callbacks ();
return WEECHAT_RC_OK;
}
/*
* Ends trigger plugin.
*/
int
weechat_plugin_end (struct t_weechat_plugin *plugin)
{
/* make C compiler happy */
(void) plugin;
trigger_config_write ();
trigger_config_free ();
trigger_callback_end ();
return WEECHAT_RC_OK;
}
+129
View File
@@ -0,0 +1,129 @@
/*
* Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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.
*
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __WEECHAT_TRIGGER_H
#define __WEECHAT_TRIGGER_H 1
#include <regex.h>
#define weechat_plugin weechat_trigger_plugin
#define TRIGGER_PLUGIN_NAME "trigger"
enum t_trigger_option
{
TRIGGER_OPTION_ENABLED = 0, /* true if trigger is enabled */
TRIGGER_OPTION_HOOK, /* hook (signal, modifier, ...) */
TRIGGER_OPTION_ARGUMENTS, /* arguments for hook */
TRIGGER_OPTION_CONDITIONS, /* conditions for trigger */
TRIGGER_OPTION_REGEX, /* replace text with 1 or more regex */
TRIGGER_OPTION_COMMAND, /* command run if conditions are OK */
TRIGGER_OPTION_RETURN_CODE, /* return code for hook callback */
/* number of trigger options */
TRIGGER_NUM_OPTIONS,
};
enum t_trigger_hook_type
{
TRIGGER_HOOK_SIGNAL = 0,
TRIGGER_HOOK_HSIGNAL,
TRIGGER_HOOK_MODIFIER,
TRIGGER_HOOK_PRINT,
TRIGGER_HOOK_TIMER,
/* number of hook types */
TRIGGER_NUM_HOOK_TYPES,
};
enum t_trigger_return_code
{
TRIGGER_RC_OK = 0,
TRIGGER_RC_OK_EAT,
TRIGGER_RC_ERROR,
/* number of return codes */
TRIGGER_NUM_RETURN_CODES,
};
struct t_trigger_regex
{
char *str_regex; /* regex to search for replacement */
regex_t *regex; /* compiled regex */
char *replace; /* replacement text */
char *replace_eval; /* evaluatued replacement text */
};
struct t_trigger
{
/* user choices */
char *name; /* trigger name */
struct t_config_option *options[TRIGGER_NUM_OPTIONS];
/* internal vars */
/* regular expressions with their replacement text */
int regex_count; /* number of regex/replacement */
struct t_trigger_regex *regex; /* array of regex/replacement */
/* hooks */
int hooks_count; /* number of hooks */
struct t_hook **hooks; /* array of hooks (signal, ...) */
unsigned long hook_count_cb; /* number of calls made to callback */
unsigned long hook_count_cmd; /* number of commands run in callback*/
int hook_running; /* 1 if one hook callback is running */
char *hook_print_buffers; /* buffers (for hook_print only) */
/* links to other triggers */
struct t_trigger *prev_trigger; /* link to previous trigger */
struct t_trigger *next_trigger; /* link to next trigger */
};
extern struct t_weechat_plugin *weechat_trigger_plugin;
extern char *trigger_option_string[];
extern char *trigger_option_default[];
extern char *trigger_hook_type_string[];
extern int trigger_return_code[];
extern struct t_trigger *triggers;
extern struct t_trigger *last_trigger;
extern int triggers_count;
extern struct t_trigger *triggers_temp;
extern struct t_trigger *last_trigger_temp;
extern int trigger_search_option (const char *option_name);
extern int trigger_search_hook_type (const char *type);
extern struct t_trigger *trigger_search (const char *name);
extern struct t_trigger *trigger_search_with_option (struct t_config_option *option);
extern void trigger_set_regex (struct t_trigger *trigger);
extern void trigger_unhook (struct t_trigger *trigger);
extern void trigger_hook (struct t_trigger *trigger);
extern struct t_trigger *trigger_alloc (const char *name);
extern void trigger_add (struct t_trigger *trigger, struct t_trigger **triggers,
struct t_trigger **last_trigger);
extern struct t_trigger *trigger_new_with_options (const char *name,
struct t_config_option **options);
extern struct t_trigger *trigger_new (const char *name,
const char *enabled,
const char *hook,
const char *arguments,
const char *conditions,
const char *replace,
const char *command,
const char *return_code);
extern void trigger_rename (struct t_trigger *trigger, const char *name);
extern void trigger_free (struct t_trigger *trigger);
extern void trigger_free_all ();
#endif /* __WEECHAT_TRIGGER_H */