/* Main processing code for Services.
 *
 * (C) 2003 Anope Team
 * Contact us at info@anope.org
 *
 * Please read COPYING and README for furhter details.
 *
 * Based on the original code of Epona by Lara.
 * Based on the original code of Services by Andy Church.
 *
 * $Id: process.c 5 2004-03-29 01:29:50Z dane $
 *
 */

#include "services.h"
#include "messages.h"
#include "modules.h"
extern Module *mod_current_module;
extern char *mod_current_module_name;
extern User *mod_current_user;
extern int mod_current_op;
extern char *mod_current_buffer;
/*************************************************************************/
/*************************************************************************/

/* Use ignore code? */
int allow_ignore = 1;

/* People to ignore (hashed by first character of nick). */
IgnoreData *ignore[256];

/*************************************************************************/

/* add_ignore: Add someone to the ignorance list for the next `delta'
 *             seconds.
 */

void add_ignore(const char *nick, time_t delta)
{
    IgnoreData *ign;
    char who[NICKMAX];
    time_t now = time(NULL);
    IgnoreData **whichlist = &ignore[tolower(nick[0])];

    strscpy(who, nick, NICKMAX);
    for (ign = *whichlist; ign; ign = ign->next) {
        if (stricmp(ign->who, who) == 0)
            break;
    }
    if (ign) {
        if (ign->time > now)
            ign->time += delta;
        else
            ign->time = now + delta;
    } else {
        ign = scalloc(sizeof(*ign), 1);
        strscpy(ign->who, who, sizeof(ign->who));
        ign->time = now + delta;
        ign->next = *whichlist;
        *whichlist = ign;
    }
}

/*************************************************************************/

/* get_ignore: Retrieve an ignorance record for a nick.  If the nick isn't
 *             being ignored, return NULL and flush the record from the
 *             in-core list if it exists (i.e. ignore timed out).
 */

IgnoreData *get_ignore(const char *nick)
{
    IgnoreData *ign, *prev;
    time_t now = time(NULL);
    IgnoreData **whichlist = &ignore[tolower(nick[0])];
    User *u = finduser(nick);
    IgnoreData **whichlist2 = NULL;
    // Bleah, this doesn't work. I need a way to get the first char of u->username.
    //if (u) whichlist2 = &ignore[tolower(u->username[0])];
    IgnoreData **whichlistast = &ignore[42];    /* * */
    IgnoreData **whichlistqst = &ignore[63];    /* ? */
    int finished = 0;
    for (ign = *whichlist, prev = NULL; ign; prev = ign, ign = ign->next) {
        if (stricmp(ign->who, nick) == 0) {
            finished = 1;
            break;
        }
    }
    if (!finished && whichlist2) {
        for (ign = *whichlist2, prev = NULL; ign;
             prev = ign, ign = ign->next) {
            if (match_usermask(ign->who, u)) {
                finished = 1;
                break;
            }
        }
    }
    if (!finished) {
        for (ign = *whichlistast, prev = NULL; ign;
             prev = ign, ign = ign->next) {
            if (match_usermask(ign->who, u)) {
                finished = 1;
                break;
            }
        }
    }
    if (!finished) {
        for (ign = *whichlistqst, prev = NULL; ign;
             prev = ign, ign = ign->next) {
            if (match_usermask(ign->who, u)) {
                finished = 1;
                break;
            }
        }
    }
    if (ign && ign->time <= now) {
        if (prev)
            prev->next = ign->next;
        else
            *whichlist = ign->next;
        free(ign);
        ign = NULL;
    }
    return ign;
}

/*************************************************************************/
/*************************************************************************/

/* split_buf:  Split a buffer into arguments and store the arguments in an
 *             argument vector pointed to by argv (which will be malloc'd
 *             as necessary); return the argument count.  If colon_special
 *             is non-zero, then treat a parameter with a leading ':' as
 *             the last parameter of the line, per the IRC RFC.  Destroys
 *             the buffer by side effect.
 */

int split_buf(char *buf, char ***argv, int colon_special)
{
    int argvsize = 8;
    int argc;
    char *s;

    *argv = scalloc(sizeof(char *) * argvsize, 1);
    argc = 0;
    while (*buf) {
        if (argc == argvsize) {
            argvsize += 8;
            *argv = srealloc(*argv, sizeof(char *) * argvsize);
        }
        if (*buf == ':') {
            (*argv)[argc++] = buf + 1;
            buf = "";
        } else {
            s = strpbrk(buf, " ");
            if (s) {
                *s++ = 0;
                while (*s == ' ')
                    s++;
            } else {
                s = buf + strlen(buf);
            }
            (*argv)[argc++] = buf;
            buf = s;
        }
    }
    return argc;
}

/*************************************************************************/

/* process:  Main processing routine.  Takes the string in inbuf (global
 *           variable) and does something appropriate with it. */

void process()
{
    int retVal = 0;
    Message *current = NULL;
    char source[64];
    char cmd[64];
    char buf[512];              /* Longest legal IRC command line */
    char *s;
    int ac;                     /* Parameters for the command */
    char **av;
    Message *m;


    /* If debugging, log the buffer */
    if (debug)
        alog("debug: Received: %s", inbuf);

    /* First make a copy of the buffer so we have the original in case we
     * crash - in that case, we want to know what we crashed on. */
    strscpy(buf, inbuf, sizeof(buf));

    doCleanBuffer((char *) buf);

    /* Split the buffer into pieces. */
    if (*buf == ':') {
        s = strpbrk(buf, " ");
        if (!s)
            return;
        *s = 0;
        while (isspace(*++s));
        strscpy(source, buf + 1, sizeof(source));
        memmove(buf, s, strlen(s) + 1);
    } else {
        *source = 0;
    }
    if (!*buf)
        return;
    s = strpbrk(buf, " ");
    if (s) {
        *s = 0;
        while (isspace(*++s));
    } else
        s = buf + strlen(buf);
    strscpy(cmd, buf, sizeof(cmd));
    ac = split_buf(s, &av, 1);
    if (mod_current_buffer) {
        free(mod_current_buffer);
    }
    if (av[1]) {
        mod_current_buffer = sstrdup(av[1]);
    } else {
        mod_current_buffer = NULL;
    }
    /* Do something with the message. */
    m = find_message(cmd);
    if (m) {
        if (m->func) {
            mod_current_module_name = m->mod_name;
            retVal = m->func(source, ac, av);
            mod_current_module_name = NULL;
            if (retVal == MOD_CONT) {
                current = m->next;
                while (current && current->func && retVal == MOD_CONT) {
                    mod_current_module_name = m->mod_name;
                    retVal = current->func(source, ac, av);
                    mod_current_module_name = NULL;
                    current = current->next;
                }
            }
        }
    } else {
        if (debug)
            alog("unknown message from server (%s)", inbuf);
    }
    if (mod_current_op == 1) {
        alog("trying to load [%s]", mod_current_module->name);
        alog("status: [%d]",
             loadModule(mod_current_module, mod_current_user));
        mod_current_module = NULL;
        mod_current_user = NULL;
        mod_current_op = 0;
    } else if (mod_current_op == 2) {
        alog("trying to unload [%s]", mod_current_module->name);
        alog("status: [%d]",
             unloadModule(mod_current_module, mod_current_user));
        mod_current_module = NULL;
        mod_current_user = NULL;
        mod_current_op = 0;
    }
    /* Free argument list we created */
    free(av);
}

/*************************************************************************/
