/* Main processing code for Services.
 *
 * IRC Services is copyright (c) 1996-2009 Andrew Church.
 *     E-mail: <achurch@achurch.org>
 * Parts written by Andrew Kempe and others.
 * This program is free but copyrighted software; see the file COPYING for
 * details.
 */

#include "services.h"
#include "modules.h"
#include "messages.h"
#include "ignore.h"

static int cb_recvmsg = -1;

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

/* split_buf:  Split a buffer into arguments and store a pointer to the
 *             argument vector in argv_ptr; return the argument count.
 *             The argument vector will point to a static buffer;
 *             subsequent calls will overwrite this buffer.
 *             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.
 */

static char **sbargv = NULL;

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

    if (!sbargv)
	sbargv = smalloc(sizeof(char *) * argvsize);
    argc = 0;
    while (*buf) {
	if (argc == argvsize) {
	    argvsize += 8;
	    sbargv = srealloc(sbargv, sizeof(char *) * argvsize);
	}
	if (*buf == ':' && colon_special) {
	    sbargv[argc++] = buf+1;
	    *buf = 0;
	} else {
	    s = strpbrk(buf, " ");
	    if (s) {
		*s++ = 0;
		while (*s == ' ')
		    s++;
	    } else {
		s = buf + strlen(buf);
	    }
	    sbargv[argc++] = buf;
	    buf = s;
	}
    }
    *argv_ptr = sbargv;
    return argc;
}

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

int process_init(int ac, char **av)
{
    cb_recvmsg = register_callback(NULL, "receive message");
    if (cb_recvmsg < 0) {
	log("process_init: register_callback() failed\n");
	return 0;
    }
    return 1;
}

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

void process_cleanup(void)
{
    unregister_callback(NULL, cb_recvmsg);
    free(sbargv);
    sbargv = NULL;
}

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

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

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


    /* If debugging, log the buffer. */
    if (debug)
	log("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));

    /* Split the buffer into pieces. */
    if (*buf == ':') {
	s = strpbrk(buf, " ");
	if (!s)
	    return;
	*s = 0;
	while (isspace(*++s))
	    ;
	strscpy(source, buf+1, sizeof(source));
	strmove(buf, s);
    } 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);

    /* Do something with the message. */
    if (call_callback_4(NULL, cb_recvmsg, source, cmd, ac, av) <= 0) {
	if (!source && stricmp(cmd, "NICK") != 0) {
	    log("Source missing for `%s' message from server (%s)",cmd,inbuf);
	} else {
	    Message *m = find_message(cmd);
	    if (m) {
		if (m->func)
		    m->func(source, ac, av);
	    } else {
		log("unknown message from server (%s)", inbuf);
	    }
	}
    }

    /* Finally, clear the first byte of `inbuf' to signal that we're
     * finished processing. */
    *inbuf = 0;
}

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