/* Autoconf patching by David Hedbor, neotron@lysator.liu.se */
/*********************************************************************/
/* file: action.c - funtions related to the action command */
/* TINTIN III */
/* (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t */
/* coded by peter unold 1992 */
/*********************************************************************/
#include <ctype.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#include "tintin.h"
#include <readline/readline.h>
extern struct session *activesession;
extern struct listnode *common_actions;
extern char vars[10][BUFFER_SIZE]; /* the &0, %1, %2,....%9 variables */
extern int term_echoing;
extern int readline_echoing_p;
extern int echo;
extern char tintin_char;
extern int acnum;
extern int mesvar[6];
extern char *get_arg_in_braces();
extern struct listnode *search_node_with_wild();
extern struct listnode *searchnode_list();
extern struct listnode *deletenode_list();
extern int case_insensitive; /* @@@added -- perry */
void substitute_vars();
int var_len[10];
char *var_ptr[10];
/***********************/
/* the #action command */
/***********************/
/* Priority code added by Joann Ellsworth 2/2/94 */
void action_command(arg, ses)
char *arg;
struct session *ses;
{
char left[BUFFER_SIZE], right[BUFFER_SIZE], result[BUFFER_SIZE];
char pr[BUFFER_SIZE];
struct listnode *myactions, *ln;
myactions = (ses) ? ses->actions : common_actions;
arg = get_arg_in_braces(arg, left, 0);
arg = get_arg_in_braces(arg, right, 1);
arg = get_arg_in_braces(arg, pr, 1);
if (!*pr)
strcpy(pr, "5"); /* defaults priority to 5 if no value given */
if (!*left) {
tintin_puts2("#Defined actions:", ses);
show_list_action(myactions);
prompt(ses);
}
else if (*left && !*right) {
if ((ln = search_node_with_wild(myactions, left)) != NULL) {
do {
shownode_list(ln);
} while ((ln = search_node_with_wild(ln->next, left)));
prompt(ses);
}
else if (mesvar[1])
tintin_puts("#That action is not defined.", ses);
}
else {
if ((ln = searchnode_list(myactions, left)) != NULL)
deletenode_list(myactions, ln);
insertnode_list(myactions, left, right, pr, PRIORITY);
if (mesvar[1]) {
sprintf(result, "#Ok. {%s} now triggers {%s} @ {%s}", left, right, pr);
tintin_puts2(result, ses);
}
acnum++;
}
}
/*************************/
/* the #unaction command */
/*************************/
void unaction_command(arg, ses)
char *arg;
struct session *ses;
{
char left[BUFFER_SIZE], result[BUFFER_SIZE], buf[8192];
struct listnode *myactions, *ln, *temp;
int flag;
flag = FALSE;
myactions = (ses) ? ses->actions : common_actions;
temp = myactions;
arg = get_arg_in_braces(arg, left, 1);
while ((ln = search_node_with_wild(temp, left)) != NULL) {
if (mesvar[1]) {
sprintf(result, "#Ok. {%s} is no longer a trigger.", ln->left);
tintin_puts2(result, ses);
}
/* @@@changed -- perry (ln is deleted and free'd by deletenode!!!)
deletenode_list(myactions, ln);
temp = ln;
*/
temp = deletenode_list(myactions, ln);
flag = TRUE;
}
if (!flag && mesvar[1]) {
sprintf(result, "#No match(es) found for {%s}", left);
tintin_puts2(result, ses);
}
}
/**************************************************************************/
/* run throught each of the commands on the right side of an alias/action */
/* expression, call substitute_text() for all commands but #alias/#action */
/**************************************************************************/
void prepare_actionalias(string, result, ses)
char *string;
char *result;
struct session *ses;
{
char arg[BUFFER_SIZE];
*result = '\0';
substitute_vars(string, arg);
substitute_myvars(arg, result, ses);
}
/*************************************************************************/
/* copy the arg text into the result-space, but substitute the variables */
/* %0..%9 with the real variables */
/*************************************************************************/
void substitute_vars(arg, result)
char *arg;
char *result;
{
int nest = 0;
int numands, n;
char *ptr;
while (*arg) {
if (*arg == '%') { /* substitute variable */
numands = 0;
while (*(arg + numands) == '%')
numands++;
if (isdigit(*(arg + numands)) && numands == (nest + 1)) {
n = *(arg + numands) - '0';
strcpy(result, vars[n]);
arg = arg + numands + 1;
result += strlen(vars[n]);
}
else {
strncpy(result, arg, numands + 1);
arg += numands + 1;
result += numands + 1;
}
}
if (*arg == '$') { /* substitute variable */
numands = 0;
while (*(arg + numands) == '$')
numands++;
if (isdigit(*(arg + numands)) && numands == (nest + 1)) {
n = *(arg + numands) - '0';
ptr = vars[n];
while (*ptr) {
if (*ptr == ';')
ptr++;
else
*result++ = *ptr++;
}
arg = arg + numands + 1;
}
else {
strncpy(result, arg, numands);
arg += numands;
result += numands;
}
}
else if (*arg == DEFAULT_OPEN) {
nest++;
*result++ = *arg++;
}
else if (*arg == DEFAULT_CLOSE) {
nest--;
*result++ = *arg++;
}
else if (*arg == '\\' && nest == 0) {
while (*arg == '\\')
*result++ = *arg++;
if (*arg == '%') {
result--;
*result++ = *arg++;
*result++ = *arg++;
}
}
else
*result++ = *arg++;
}
*result = '\0';
}
/**********************************************/
/* check actions from a sessions against line */
/**********************************************/
void check_all_actions(line, ses)
char *line;
struct session *ses;
{
struct listnode *ln;
static char temp[BUFFER_SIZE] = PROMPT_FOR_PW_TEXT;
char strng[BUFFER_SIZE];
if (check_one_action(line, temp, ses) && ses == activesession) {
term_echoing = FALSE;
readline_echoing_p = 0; /* this tells readline to quit echoing */
}
ln = (ses) ? ses->actions : common_actions;
while ((ln = ln->next)) {
if (check_one_action(line, ln->left, ses)) {
char buffer[BUFFER_SIZE];
prepare_actionalias(ln->right, buffer, ses);
if (echo && activesession == ses) {
sprintf(strng, "[ACTION: %s]", buffer);
tintin_puts2(strng, activesession);
}
parse_input(buffer, ses);
return;
}
}
}
int match_a_string(line, mask)
char *line;
char *mask;
{
char *lptr, *mptr;
lptr = line;
mptr = mask;
while (*lptr && *mptr && !(*mptr == '%' && isdigit(*(mptr + 1)))) {
/* @@@changed -- perry */
if (case_insensitive && tolower(*lptr) != tolower(*mptr))
return -1;
else if (!case_insensitive && *lptr != *mptr)
return -1;
lptr++, mptr++;
}
if (!*mptr || (*mptr == '%' && isdigit(*(mptr + 1))))
return ((int)(lptr - line));
return -1;
}
int check_one_action(line, action, ses)
char *line;
char *action;
struct session *ses;
{
int i;
if (check_a_action(line, action, ses)) {
for (i = 0; i < 10; i++) {
if (var_len[i] != -1) {
strncpy(vars[i], var_ptr[i], var_len[i]);
*(vars[i] + var_len[i]) = '\0';
}
}
return TRUE;
}
else
return FALSE;
}
/******************************************************************/
/* check if a text triggers an action and fill into the variables */
/* return TRUE if triggered */
/******************************************************************/
int check_a_action(line, action, ses)
char *line;
char *action;
struct session *ses;
{
char result[BUFFER_SIZE];
char *temp2, *tptr, *lptr, *lptr2;
int i, flag_anchor, count, len, flag;
for (i = 0; i < 10; i++)
var_len[i] = -1;
flag_anchor = FALSE;
lptr = line;
substitute_myvars(action, result, ses);
tptr = result;
if (*tptr == '^') {
tptr++;
flag_anchor = TRUE;
/* CHANGED to fix a bug with #action {^%0 foo}
* Thanks to Spencer Sun for the bug report (AND fix!)
if (*tptr!=*line)
return FALSE;
*/
}
if (flag_anchor) {
if ((len = match_a_string(lptr, tptr)) == -1)
return FALSE;
lptr += len;
tptr += len;
}
else {
flag = TRUE;
len = -1;
while (*lptr && flag) {
if ((len = match_a_string(lptr, tptr)) != -1) {
flag = FALSE;
}
else
lptr++;
}
if (len != -1) {
lptr += len;
tptr += len;
}
else
return FALSE;
}
while (*lptr && *tptr) {
temp2 = tptr + 2;
if (!*temp2) {
var_len[*(tptr + 1) - 48] = strlen(lptr);
var_ptr[*(tptr + 1) - 48] = lptr;
return TRUE;
}
lptr2 = lptr;
flag = TRUE;
len = -1;
while (*lptr2 && flag) {
if ((len = match_a_string(lptr2, temp2)) != -1) {
flag = FALSE;
}
else
lptr2++;
}
if (len != -1) {
var_len[*(tptr + 1) - 48] = lptr2 - lptr;
var_ptr[*(tptr + 1) - 48] = lptr;
lptr = lptr2 + len;
tptr = temp2 + len;
}
else {
return FALSE;
}
}
if (*tptr)
return FALSE;
else
return TRUE;
}