#include <stdio.h>
#include <string.h>
#include "/home/spencep/xchat-1.8.3/src/common/xchat.h"
#include "/home/spencep/xchat-1.8.3/src/common/plugin.h"
/* these next 2 headers are here because I *hate* **warnings** when i compile */
#include "/home/spencep/xchat-1.8.3/src/common/outbound.h"
#include "/home/spencep/xchat-1.8.3/src/common/text.h"

#define CHANSERV "ChanServ" //name of channel services bot
#define OP "/cs op %s %s" //while blitzed doesn't need a nick parm, other nets do so i leave it in
#define UNBAN "/cs unban %s %s" //once again I don't need a nick parm, but other nets do so thats what the second one is
#define UNBANNED "You have been unbanned from" //partial string to match from an unban command
#define KICKMSG "Bastard!"
#define BANMSG "Well double dumbass on you!"

extern	struct module *module_find (char *name);

int channelop(struct session *sess, char *chan, char *opping, char *opped, void *a, void *b);
int channeldeop(struct session *sess, char *chan, char *deopping, char *deopped, void *a, void *b);
int servermsg(struct session *sess, char *serv, char *message, void *a, void *b, void *c);
int kickreact(struct session *sess, char *kicker,char *chan);
int banreact(struct session *sess,char *chan);
int noticereact(struct session *sess, char *from, char *to, char *message);

char *name = "SpenceDefense by CrazySpence";
char *desc = "Defense script to respond to kicks bans and deops";

struct	xp_signal chanop_sig, chandeop_sig, servermsg_sig;

struct shitty {
        char nick[32];
        char ident[10];
        char host[255];
        char chan[255];
        int active;
};

struct shitty bastard;
struct shitty last_bastard;

int     (*chanop_next) (void *, void *, void *, void *, void *,char);
int     (*chandeop_next) (void *, void *, void *, void *, void *,char);
int     (*servermsg_next) (void *, void *, void *, void *, void *,char);

int	module_init (int ver, struct module *mod, struct session *sess)
{
        /* This check *MUST* be done first */
	if (ver != MODULE_IFACE_VER)
		return 1;

	if (module_find (name) != NULL) {
		/* We are already loaded */
		PrintText(sess, "Defense grid already enabled\n");
		return 1;
	}

        PrintText(sess, "Defense grid enabled\n");
	mod->name = name;
	mod->desc = desc;

        bastard.nick[0] = 0;
        bastard.ident[0] = 0;
        bastard.host[0] = 0;
        bastard.chan[0] = 0;
        bastard.active = 0;
        last_bastard = bastard;
        chanop_sig.signal = XP_CHANOP;
        chanop_sig.callback = XP_CALLBACK(channelop);
        chanop_sig.naddr = &chanop_next;
        chanop_sig.mod = mod;

        hook_signal(&chanop_sig);

        chandeop_sig.signal = XP_CHANDEOP;
        chandeop_sig.callback = XP_CALLBACK(channeldeop);
        chandeop_sig.naddr = &chandeop_next;
        chandeop_sig.mod = mod;

        hook_signal(&chandeop_sig);

        servermsg_sig.signal = XP_INBOUND;
        servermsg_sig.callback = XP_CALLBACK(servermsg);
        servermsg_sig.naddr = &servermsg_next;
        servermsg_sig.mod = mod;

        hook_signal(&servermsg_sig);

        return 0;
}

void module_cleanup (struct module *mod, struct session *sess)
{
	PrintText(sess, "Lowering Defense grid....\n");
}

int channelop(struct session *sess, char *chan, char *opping, char *opped, void *a, void *b) {
        char buf[512];
        if (bastard.active == 1) { //a bastard has been set
                 if (strcasecmp(chan,bastard.chan) == 0) { //check if it was for this channel
                       // snprintf(buf,510,"Theres a bastard for %s in %s\n",bastard.nick,bastard.chan);
                       // PrintText(sess,buf);
                        if (strcasecmp(bastard.nick,last_bastard.nick) == 0 && strcasecmp(bastard.host,last_bastard.host) == 0) {
                                snprintf(buf,510,"/ban *!%s@%s\n",bastard.ident,bastard.host);
                                handle_command(buf,sess,FALSE,FALSE);
                                snprintf(buf,510,"/kick %s %s\n",bastard.nick,BANMSG);
                                handle_command(buf,sess,FALSE,FALSE);
                        } else {
                                snprintf(buf,510,"/kick %s %s\n",bastard.nick,KICKMSG); //Kick!
                                handle_command(buf,sess,FALSE,FALSE);
                        }
                        last_bastard = bastard;
                        bastard.nick[0] = 0; //reset bastard struct
                        bastard.ident[0] = 0;
                        bastard.host[0] = 0;
                        bastard.chan[0] = 0;
                        bastard.active = 0;
                }
        }
      /*if (strcmp(opped,sess->server->nick) == 0) {
                snprintf(buf,510,"/msg %s Thanks for the ops %s\n",chan,opping);
                handle_command(buf,sess,FALSE,FALSE);
        } */
        XP_CALLNEXT(chanop_next,sess,chan,opping,opped,a,b);
}

int channeldeop(struct session *sess, char *chan, char *deopping, char *deopped, void *a, void *b) {
        char buf[512];

        if (strcmp(deopped,sess->server->nick) == 0) {
                if (strcmp(deopped,deopping) != 0) {
                        snprintf(buf,510,OP,chan,sess->server->nick);
                        handle_command(buf,sess,FALSE,FALSE);
                }
        }
        XP_CALLNEXT(chanop_next,sess,chan,deopping,deopped,a,b);
}

int servermsg(struct session *sess, char *serv, char *message, void *a, void *b, void *c) {
        //char buf[512];
        char *s;
        char *parse[4];
        char backup[512];
        char *kick[2];
        char *banchan;
        strcpy(backup,message);  //i found out if you use message in the strtok you break how everything looks...lol
        s = strtok(backup," ");
        parse[0] = s; //from
        s = strtok(NULL," ");
        parse[1] = s; //command
        s = strtok(NULL, " ");
        parse[2] = s; //to
        s = strtok(NULL,"\n");
        if (s != 0) parse[3] = s; //extra args IF there are any

        strcpy(backup,parse[0]); //Get the preceeding : out of the way
        s = strtok(backup,":\n");
        parse[0] = s;

        if (strcmp(parse[1],"KICK") == 0) { //A kick happened somewhere
                s = strtok(parse[3]," ");
                kick[0] = s;
                s = strtok(NULL," ");
                if (s != 0) kick[1] = s;
                if (strcmp(kick[0],sess->server->nick) == 0) //check if you were kicked
                        kickreact(sess,parse[0],parse[2]);
        }

        if (strcmp(parse[1],"474") == 0) { //I am banned!!!
                s = strtok(parse[3]," ");
                banchan = s;
                banreact(sess,banchan);
        }

        if (strcmp(parse[1],"NOTICE") == 0) { //I've been noticed
                noticereact(sess,parse[0],parse[2],parse[3]);
        }
      //  snprintf(buf,510,"From: %s\n",parse[2]);
      //  PrintText(sess,buf);
        XP_CALLNEXT(servermsg_next,sess,serv,message,a,b,c);
}

int kickreact(struct session *sess,char *kicker,char *chan) {
        char buf[512];
        char *s;
        char *parse[3];
        s = strtok(kicker,"!"); //split the nick!ident@host
        parse[0] = s;
        s = strtok(NULL,"@");
        parse[1] = s;
        s = strtok(NULL,"\n");
        parse[2] = s;
        strcpy(bastard.nick,parse[0]); //set the bastard
        strcpy(bastard.ident,parse[1]);
        strcpy(bastard.host,parse[2]);
        strcpy(bastard.chan,chan);
        bastard.active = 1; //activate the bastard
        snprintf(buf,510,"/join %s\n",chan);
        handle_command(buf,sess,FALSE,FALSE);
        return 0;
}

int banreact(struct session *sess,char *chan) {
        char buf[512];
        snprintf(buf,510,UNBAN,chan,sess->server->nick);
        handle_command(buf,sess,FALSE,FALSE); //unban me!
        return 0;
}

int noticereact(struct session *sess, char *from, char *to, char *message) {
        char buf[512];
        char *s;
        char *parse[3];
        char *chan;

        s = strtok(from,"!"); //split the nick!ident@host
        parse[0] = s;
        s = strtok(NULL,"@");
        parse[1] = s;
        s = strtok(NULL,"\n");
        parse[2] = s;

        if (strcmp(CHANSERV,parse[0]) == 0) {
                if(strstr(message,UNBANNED)) { //Recieved notice that I was unbanned
                        s = strtok(message,"#");
                        s = strtok(NULL,"\002");//Parse channel name
                        chan = s;
                        snprintf(buf,510,"/join #%s",chan);
                        handle_command(buf,sess,FALSE,FALSE);//Rejoin Channel
                }
        }
        return 0;
}
