/* Copyright (c) 2002
 *	Marko Boomstra (m.boomstra@chello.nl).  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#include <conf.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <ncurses.h>
#include <panel.h>
#include "mudix.h"


void show_triggers(void)
{
    static int		 current;
    	   TRIGGER 	*trig;
    	   char    	*str;
    	   int      	 line, i, width, height, centre, wsize;

    width  = LEN_COL-4;
    height = 20;
    wsize  = height-2;
    centre = ((width-2)/2)-1;

    wresize(wMsg, height, width);
    werase(wMsg);
    move_panel(pMsg, 1, 2);

    if (panel_hidden(pMsg) == PANEL_HIDDEN)
	current = 0;

    for (line=1, i=0, trig = settings->trigger_list; trig; trig = trig->next) {
    	if (!trig->in || !trig->out)
            continue;

	i+=2;
	if (i < (current*wsize)+2)
	    continue;

      	mvwprintw(wMsg, line++, 1, "%2d%c (%2d): %s",
		(i/2), trig->enabled? '*': ' ', trig->level, trig->in); 
      	mvwprintw(wMsg, line++, 1, "Response: %s", 
		trig->level == TRG_PASSWORD?  "*********": trig->out); 

	if (line >= wsize && trig->next) {
	    current++;
	    break;
	}

	if (!trig->next)	/* last one */
	    current = 0;
    }

    draw_border(wMsg);
    str = "Triggers";
    mvwprintw(wMsg, 0, centre-strlen(str)/2, str);
    show_panel(pMsg);
    return;
}

TRIGGER *new_trigger(int level, bool last)
{
    TRIGGER *trigger;

    if (!(trigger = (TRIGGER *)malloc(sizeof(TRIGGER))))
	return NULL; 
     
    if (last && settings->trigger_list) {
        TRIGGER *iTrig;

        for (iTrig = settings->trigger_list; iTrig; iTrig = iTrig->next) {
            if (!iTrig->next)
                break;
        }
        iTrig->next = trigger;
        trigger->next = NULL;
    }
    else {
    	trigger->next = settings->trigger_list;
    	settings->trigger_list = trigger;
    }

    trigger->in 	   = NULL;
    trigger->out	   = NULL;
    trigger->inp 	   = NULL;
    trigger->pArg 	   = trigger->arg;
    trigger->enabled	   = FALSE;
    trigger->level	   = level;

    return trigger;
}

void free_trigger(TRIGGER *trigger)
{
    TRIGGER *lookup;

    if (!trigger)
	return;

    for (lookup = settings->trigger_list; lookup; lookup = lookup->next) {
        if (lookup->next == trigger) {
            lookup->next = trigger->next;
            break;
        }
    }

    if (trigger == settings->trigger_list)
        settings->trigger_list = trigger->next;

    if (trigger->in)
	free(trigger->in);
    if (trigger->out)
	free(trigger->out);
    trigger->inp = NULL;

    free(trigger);
    return;
}

TRIGGER *trig_lookup(TRIGGER *beg, int level)
{
    TRIGGER *trig;

    for (trig = (beg? beg: settings->trigger_list); trig; trig = trig->next) {
	if (!trig->in || !trig->out)
	    continue;

	if (trig->level == level)
	    break;
    }

    return trig;
}

#define MAX_TRIG_ARG_LEN	(LINE_MAXIM-20)

void trigger_check(char *buffer)
{
    TRIGGER *trig;
    char    *pBuf, *pTrg, *pArg, *pMrk;
    
    for (trig = settings->trigger_list; trig; trig = trig->next) 
    {
    	if (!trig->enabled)
        {
            continue;
        }
        
        pBuf = buffer;
        pTrg = trig->inp;
        pArg = trig->pArg;
        pMrk = NULL;
        while (*pBuf)
        {
            /* first check if the character is printable (NL/CR?) */
            if (!isprint(*pBuf)) 
            {
                /* nope, then set our pointers to start */
                pArg = trig->pArg = trig->arg;
                pTrg = trig->in;
                pMrk = NULL;
                pBuf++;
                continue;
            }

            /* not inside an argument, and buffer unequal to trigger? */
            if (*pTrg != *pBuf && *pTrg != '%' && pArg == trig->pArg)
            {
                /* backup pointers, but this time continue with next if */
                pArg = trig->pArg = trig->arg;
                pTrg = trig->in;
                pMrk = NULL;
            }

            /* check for a %0-%9 */
            if (*pTrg == '%')
            {
                pTrg++;
                if (isdigit(*pTrg++))
                {
                    /* if we are already within another %, close that one */
		    if (pArg != trig->pArg)
                    {
                        *pArg++ = '}';
                        trig->pArg = pArg;
                    }

                    /* did we place a marker? if so clear it */
                    if (pMrk)
                    {
                        pMrk = NULL;
                    }

                    /* start a new argument in our arg buffer */
		    *pArg++ = '{';
                }
            }

            /* is the character in the trigger equal to the incoming buffer? */
            if (*pTrg != *pBuf)
            {
                /* nope, characters not the same... check if in an argument */
                if (pArg != trig->pArg)
                {
                    /* yup, did we place a marker? */
                    if (pMrk)
                    {
                        char *pTmp = pMrk;

                        /* copy everything from the marker into argument */
                        while (pTmp != pTrg)
                        {
                            *pArg++ = *pTmp++;
                            if ((pArg - trig->arg) >= MAX_TRIG_ARG_LEN)
                            {
                                break;
                            }
                        }
                        /* backup the trigger pointer */
                        pTrg = pMrk;
                        pMrk = NULL;
                    }
                    /* copy character from buf into argument */
                    *pArg++ = *pBuf;
                }
            }
            else
            {
                /* characters are equal: if marker's not set, set it now */
	        if (!pMrk && pArg != trig->pArg)
                {
                    pMrk = pTrg;
                }
                pTrg++;
            }

            /* is last argument passing max arg length? */
            if ((pArg - trig->arg) >= MAX_TRIG_ARG_LEN)
            {
                /* set argument pointer to start of last argument */
                pArg = trig->pArg;
            }

            pBuf++;

            if (*pTrg == '\0') 
            {
            	/* trigger reached the end of its buffer */
            	if (pArg != trig->pArg)
            	{
                    *pArg++ = '\0';
            	}

            	/* call the input processor */
            	process_input(trig->out, trig->arg, TRUE);

            	/* disable triggers of level LOGIN and PASSWORD */
            	if (trig->level == TRG_LOGIN || trig->level == TRG_PASSWORD)
            	{
	            trig->enabled = FALSE;
            	}

            	/* update the pointers */
	    	pTrg = trig->inp  = trig->in;
            	pArg = trig->pArg = trig->arg;
		pMrk = NULL;
	    }
	}

        /* continue at current position in the trigger next time */
        trig->inp = pTrg;
    }

    return;
}


syntax highlighted by Code2HTML, v. 0.9.1