/*

oer - IRC bot

See ftp://nic.funet.fi/pub/unix/irc/docs/FAQ.gz section 11 for the
definition of the word bot.

Copyright (C) 2000-2002 EQU <equ@equnet.org>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "oer-common.h"
#include "oer.h"
#include "parse.h"
#include "ds.h"
#include "misc.h"

/* prototype definitions */
int serverconnection(void);
int registerconnection(void);
int handleserverdata(void);
int processtimeds(void);
int processactions(struct timed *);
void establishconnection(void);
void reconnect(void);

void reconnect()
{
	char stringbuffer[WRITE_BUFFER_LENGTH + 1];
#ifdef DEBUG
        oer_debug(OER_DEBUG_NOISE, "reconnect()\n");
#endif
	/* check if connected */
	if(mystate->current_server == NULL) {
		return;
	}
	if(mystate->reconnect == OER_RECONNECT_NONE) {
		return;
	}
	/* this is a workaround for the situation where admin changes oer's
	   nick to a taken one and then jumps/reconnects, oer should at least
	   try to get the one the admin specified or fall back to alternative */
	if(strcasecmp(mystate->nick, mystate->getnick)) {
		strncpy(mystate->nick, mystate->getnick, NICKLEN);
	}
	switch(mystate->reconnect) {
	case OER_RECONNECT_ADMIN:
		snprintf(stringbuffer, WRITE_BUFFER_LENGTH, "QUIT :%s\n", mystate->signoff);
#ifdef DEBUG
		oer_debug(OER_DEBUG_INFO, "reconnect->%s", stringbuffer);
#endif
		if(write(mystate->sockfd, stringbuffer, strlen(stringbuffer)) < 0) {
#ifdef DEBUG
			oer_debug(OER_DEBUG_ERROR, "reconnect->write failed: %s\n", strerror(errno));
#endif
		}
		mystate->current_server->tx += strlen(stringbuffer);
		close(mystate->sockfd);
		memset(&mystate->current_server->registered, 0, sizeof(struct registered));
		mystate->current_server->connected = 0;
		mystate->current_server = NULL;
		initall();
#ifdef DEBUG
		oer_debug(OER_DEBUG_INFO, "reconnect->sleeping 30 seconds to avoid throttling\n");
#endif
		sleep(OER_RECONNECT_DELAY);
		establishconnection();
		if(mystate->bailout) {
			exit(EXIT_FAILURE);
		}
		mystate->reconnect = OER_RECONNECT_NONE;
		break;
	case OER_RECONNECT_STONED:
#ifdef DEBUG
		oer_debug(OER_DEBUG_INFO, "main->current server is stoned, jumping to next one if available\n");
#endif
		close(mystate->sockfd);
                memset(&mystate->current_server->registered, 0, sizeof(struct registered));
		mystate->current_server->connected = 0;
		mystate->current_server = NULL;
		initall();
#ifdef DEBUG
		oer_debug(OER_DEBUG_INFO, "reconnect->sleeping 30 seconds to avoid throttling\n");
#endif
		sleep(OER_RECONNECT_DELAY);
		establishconnection();
		if(mystate->bailout) {
			exit(EXIT_FAILURE);
		}
		mystate->reconnect = OER_RECONNECT_NONE;
		break;
	case OER_RECONNECT_ERROR:
		if(mystate->quitting) {
#ifdef DEBUG
			oer_debug(OER_DEBUG_INFO, "reconnect->%s exiting\n", mystate->progname);
#endif
			close(mystate->sockfd);
			exit(EXIT_SUCCESS);
		}
#ifdef DEBUG
		oer_debug(OER_DEBUG_INFO, "reconnect->failed to read/write from/to current server\n");
		oer_debug(OER_DEBUG_INFO, "reconnect->jumping to next server if available\n");
#endif
		close(mystate->sockfd);
                memset(&mystate->current_server->registered, 0, sizeof(struct registered));
		mystate->current_server->connected = 0;
		mystate->current_server = NULL;
		initall();
#ifdef DEBUG
		oer_debug(OER_DEBUG_INFO, "reconnect->sleeping 30 seconds to avoid throttling\n");
#endif
		sleep(OER_RECONNECT_DELAY);
		establishconnection();
		if(mystate->bailout) {
			exit(EXIT_FAILURE);
		}
		mystate->reconnect = OER_RECONNECT_NONE;
		break;
	}
}

void establishconnection()
{
#ifdef DEBUG
        oer_debug(OER_DEBUG_NOISE, "establishconnection()\n");
#endif
	/* loop until a fatal error */
	while(!mystate->bailout) {
		mystate->now = time(NULL);
		switch(serverconnection()) {
		case OER_SERVERCONNECTION_ERR_SOCKET:
#ifdef DEBUG
			oer_debug(OER_DEBUG_FATAL, "establishconnection->socket() failed, exiting.\n");
#endif
			mystate->bailout = 1;
			return;
		case OER_SERVERCONNECTION_ERR_GETHOSTNAME:
#ifdef DEBUG
			oer_debug(OER_DEBUG_FATAL, "establishconnection->gethostname() failed, exiting.\n");
#endif
			mystate->bailout = 1;
			return;
		case OER_SERVERCONNECTION_ERR_GETHOSTBYNAME_RETRY:
#ifdef DEBUG
			oer_debug(OER_DEBUG_ERROR, "establishconnection->gethostbyname() temporary error, retrying.\n");
#endif
			sleep(OER_WAIT_BETWEEN_CONNECTION_ATTEMPTS);
			break;
		case OER_SERVERCONNECTION_ERR_GETSERVER_RETRY:
#ifdef DEBUG
			oer_debug(OER_DEBUG_ERROR, "establishconnection->getserver() temporary error, retrying.\n");
#endif
			sleep(OER_WAIT_BETWEEN_CONNECTION_ATTEMPTS);
			break;
		case OER_SERVERCONNECTION_ERR_GETHOSTBYNAME:
#ifdef DEBUG
			oer_debug(OER_DEBUG_FATAL, "establishconnection->gethostbyname() fatal error, exiting.\n");
#endif
			mystate->bailout = 1;
			return;
		case OER_SERVERCONNECTION_ERR_BIND:
#ifdef DEBUG
			oer_debug(OER_DEBUG_FATAL, "establishconnection->bind() fatal error, exiting.\n");
#endif
			mystate->bailout = 1;
			return;
		case OER_SERVERCONNECTION_ERR_CONNECT_RETRY:
#ifdef DEBUG
			oer_debug(OER_DEBUG_ERROR, "establishconnection->connect() temporary error, retrying.\n");
#endif
			sleep(OER_WAIT_BETWEEN_CONNECTION_ATTEMPTS);
			break;
		case OER_SERVERCONNECTION_ERR_CONNECT:
#ifdef DEBUG
			oer_debug(OER_DEBUG_FATAL, "establishconnection->connect() fatal error, exiting.\n");
#endif
			mystate->bailout = 1;
			return;
		case OER_SERVERCONNECTION_ALREADY_CONNECTED:
		case OER_SERVERCONNECTION_EVERYTHING_OK:
			return;
		}
	}
}

int serverconnection()
{
	struct hostent *hptr;
	struct sockaddr_in servaddr;
#ifdef DEBUG
        oer_debug(OER_DEBUG_NOISE, "serverconnection()\n");
#endif
	/* check if we are already connected */
	if(mystate->current_server != NULL) {
		if(mystate->current_server->connected) {
			return OER_SERVERCONNECTION_ALREADY_CONNECTED;
		}
	}
	if((mystate->sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
#ifdef DEBUG
		oer_debug(OER_DEBUG_ERROR, "serverconnection->socket() failed: %s\n", strerror(errno));
#endif
		return OER_SERVERCONNECTION_ERR_SOCKET;
	}
	memset(&servaddr, 0, sizeof(struct sockaddr_in));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = INADDR_ANY;
	/* if we don't have a vhost, just use the default system hostname */
	if(!mystate->vhost) {
		if(gethostname(mystate->host, HOSTLEN) < 0) {
#ifdef DEBUG
			oer_debug(OER_DEBUG_ERROR, "serverconnection->gethostname() failed: %s\n", strerror(errno));
#endif
			close(mystate->sockfd);
			return OER_SERVERCONNECTION_ERR_GETHOSTNAME;
		}
	}
	if((hptr = (struct hostent *) gethostbyname(mystate->host)) == NULL) {
#ifndef _NO_H_ERRNO
#ifdef DEBUG
		oer_debug(OER_DEBUG_ERROR, "serverconnection->gethostbyname() for %s failed (h_errono = %d)\n", mystate->host, h_errno);
#endif
		if(h_errno == TRY_AGAIN) {
#ifdef DEBUG
			oer_debug(OER_DEBUG_ERROR, "serverconnection->gethostbyname() non-fatal error\n");
#endif
			close(mystate->sockfd);
			return OER_SERVERCONNECTION_ERR_GETHOSTBYNAME_RETRY;
		} else {
			close(mystate->sockfd);
			return OER_SERVERCONNECTION_ERR_GETHOSTBYNAME;
		}
#else
		/* i'm feeling lucky, and lazy too :) */
#ifdef DEBUG
		oer_debug(OER_DEBUG_ERROR, "serverconnection->gethostbyname() unknown error\n");
#endif
		close(mystate->sockfd);
		return OER_SERVERCONNECTION_ERR_GETHOSTBYNAME_RETRY;
#endif
	}
	memcpy((char *) &servaddr.sin_addr, hptr->h_addr, hptr->h_length);
	if(mystate->vhost) {
		/* bind is only necessary for vhost */
		if(bind(mystate->sockfd, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) < 0) {
#ifdef DEBUG
			oer_debug(OER_DEBUG_ERROR, "serverconnection->bind() failed: %s (check your vhost setting)\n", strerror(errno));
#endif
			close(mystate->sockfd);
			return OER_SERVERCONNECTION_ERR_BIND;
		}
	}
	if((mystate->current_server = getserver()) == NULL) {
		/* we didn't get a server this time but we will eventually
		   once the used & stoned flags are cleared. Unless
		   ofcourse the servers are permanently unreachable. */
		close(mystate->sockfd);
		return OER_SERVERCONNECTION_ERR_GETSERVER_RETRY;
	}
	mystate->current_server->used = 1;
#ifdef DEBUG
	oer_debug(OER_DEBUG_INFO, "serverconnection->using server %s port %d\n", mystate->current_server->serverhost, mystate->current_server->serverport);
#endif
	if((hptr = (struct hostent *) gethostbyname(mystate->current_server->serverhost)) == NULL) {
#ifndef _NO_H_ERRNO
#ifdef DEBUG
		oer_debug(OER_DEBUG_ERROR, "serverconnection->gethostbyname() for %s failed (h_errno = %d)\n", mystate->current_server->serverhost, h_errno);
#endif
		if(h_errno == NO_ADDRESS || h_errno == HOST_NOT_FOUND || h_errno == TRY_AGAIN) {
#ifdef DEBUG
			oer_debug(OER_DEBUG_INFO, "serverconnection->switching to next server if available\n");
#endif
			close(mystate->sockfd);
			return OER_SERVERCONNECTION_ERR_GETHOSTBYNAME_RETRY;
		}
#else
		/* i'm feeling lucky, and lazy too :) */
#ifdef DEBUG
		oer_debug(OER_DEBUG_ERROR, "serverconnection->gethostbyname() unknown error\n");
#endif
		close(mystate->sockfd);
		return OER_SERVERCONNECTION_ERR_GETHOSTBYNAME_RETRY;
#endif
        }
	memcpy(&servaddr.sin_addr, hptr->h_addr_list[0], sizeof(struct in_addr));
	servaddr.sin_port = htons(mystate->current_server->serverport);
	if(connect(mystate->sockfd, (struct sockaddr *) &servaddr, sizeof(struct sockaddr_in)) < 0) {
#ifdef DEBUG
		oer_debug(OER_DEBUG_ERROR, "serverconnection->connect() failed: %s\n", strerror(errno));
#endif
		if(errno == ECONNREFUSED || errno == ETIMEDOUT || errno == ENETUNREACH || errno == EHOSTUNREACH) {
#ifdef DEBUG
			oer_debug(OER_DEBUG_INFO, "serverconnection->connect() non-fatal error\n");
			oer_debug(OER_DEBUG_INFO, "serverconnection->switching to next server if available\n");
#endif
			close(mystate->sockfd);
			return OER_SERVERCONNECTION_ERR_CONNECT_RETRY;
		}
		close(mystate->sockfd);
		return OER_SERVERCONNECTION_ERR_CONNECT;
	}
	mystate->current_server->connected = 1;
        mystate->current_server->rx = 0;
        mystate->current_server->tx = 0;
	mystate->current_server->linkup = mystate->now;
	return OER_SERVERCONNECTION_EVERYTHING_OK;
}

int registerconnection()
{
	char stringbuffer[WRITE_BUFFER_LENGTH + 1];
        char newuser[USERLEN + 1];
	char prefixes[TINYSTRINGLEN + 1];
	char *ptr;
	struct passwd *pwd;
#ifdef DEBUG
        oer_debug(OER_DEBUG_NOISE, "registerconnection()\n");
#endif
	/* check if connected */
	if(mystate->current_server == NULL) {
		return OER_REGISTERCONNECTION_EVERYTHING_OK;
	}
	/* check that all registration phases are complete */
	if(mystate->current_server->registered.begin
	   && mystate->current_server->registered.pass
	   && mystate->current_server->registered.nick
	   && mystate->current_server->registered.user
	   && mystate->current_server->registered.done) {
		return OER_REGISTERCONNECTION_EVERYTHING_OK;
	}
	if(!mystate->current_server->registered.begin) {
		/* BEGIN */
#ifdef DEBUG
		oer_debug(OER_DEBUG_INFO, "registerconnection->registering on the server\n");
#endif
		mystate->current_server->registered.begin = 1;
	}
	if(!mystate->current_server->registered.pass) {
		/* PASS, OPTIONAL */
		if(strlen(mystate->current_server->password)) {
			snprintf(stringbuffer, WRITE_BUFFER_LENGTH, "PASS %s\n", mystate->current_server->password);
#ifdef DEBUG
			oer_debug(OER_DEBUG_INFO, "registerconnection->%s", stringbuffer);
#endif
			if(write(mystate->sockfd, stringbuffer, strlen(stringbuffer)) < 0) {
#ifdef DEBUG
				oer_debug(OER_DEBUG_ERROR, "registerconnection->write failed: %s\n", strerror(errno));
#endif
				return OER_REGISTERCONNECTION_ERR_WRITE;
			}
			mystate->current_server->tx += strlen(stringbuffer);
		}
                mystate->current_server->registered.pass = 1;
	}
        if(!mystate->current_server->registered.nick) {
		/* NICK */
		snprintf(stringbuffer, WRITE_BUFFER_LENGTH, "NICK %s\n", mystate->nick);
#ifdef DEBUG
		oer_debug(OER_DEBUG_INFO, "registerconnection->%s", stringbuffer);
#endif
		if(write(mystate->sockfd, stringbuffer, strlen(stringbuffer)) < 0) {
#ifdef DEBUG
			oer_debug(OER_DEBUG_ERROR, "registerconnection->write failed: %s\n", strerror(errno));
#endif
			return OER_REGISTERCONNECTION_ERR_WRITE;
		}
		mystate->current_server->tx += strlen(stringbuffer);
		mystate->current_server->registered.nick = 1;
	}
	if(!mystate->current_server->registered.user) {
		if(!mystate->customuser) {
			if((pwd = getpwuid(getuid())) == NULL) {
				return OER_REGISTERCONNECTION_ERR_GETPWUID;
			}
			strncpy(mystate->user, pwd->pw_name, USERLEN);
		}
		strncpy(prefixes, CONNECTION_STATE_PREFIXES, TINYSTRINGLEN);
		ptr = mystate->user;
		while(ptr && (index(prefixes, *ptr) != NULL)) {
			/* strip the prefixes added by the server */
			ptr++;
		}
		strncpy(newuser, ptr, USERLEN);
		strncpy(mystate->user, newuser, USERLEN);
		snprintf(stringbuffer, WRITE_BUFFER_LENGTH, "USER %s %s %s :%s\n", mystate->user, mystate->host, mystate->current_server->serverhost, mystate->realname);
#ifdef DEBUG
		oer_debug(OER_DEBUG_INFO, "registerconnection->%s", stringbuffer);
#endif
		if(write(mystate->sockfd, stringbuffer, strlen(stringbuffer)) < 0) {
#ifdef DEBUG
			oer_debug(OER_DEBUG_ERROR, "registerconnection->write failed: %s\n", strerror(errno));
#endif
			return OER_REGISTERCONNECTION_ERR_WRITE;
		}
		mystate->current_server->tx += strlen(stringbuffer);
		mystate->current_server->registered.user = 1;
	}
	return OER_REGISTERCONNECTION_EVERYTHING_OK;
}

int handleserverdata()
{
	int cont;
	int i;
	char ch;
	char stringbuffer[READ_BUFFER_LENGTH + 1];
        char pong[STRINGLEN + 1];
        size_t br;
        char *ptr;
#ifdef DEBUG
        oer_debug(OER_DEBUG_NOISE, "handleserverdata()\n");
#endif
	i = 0;
	cont = 1;
        do {
                if((br = read(mystate->sockfd, &ch, 1)) < 0) {
			/* error while reading from server socket */
#ifdef DEBUG
			oer_debug(OER_DEBUG_ERROR, "handleserverdata->read failed: %s\n", strerror(errno));
#endif
			return OER_HANDLESERVERDATA_ERR_READ;
                } else if(br == 0) {
			/* nothing or EOF was returned, bail out */
			cont = 0;
		} else if(br > 0 && i < READ_BUFFER_LENGTH) {
			stringbuffer[i++] = ch;
			/* check for newline */
			if(ch == '\n') {
				cont = 0;
			}
		}
	} while(cont);
	if(!i) {
		/* zero bytes was read, bail out */
		return OER_HANDLESERVERDATA_ERR_NOTHING_READ;
	}
	stringbuffer[i] = '\0';
	/* only count reads from the server as link activity */
	mystate->current_server->lastping = mystate->now;
	mystate->current_server->rx += strlen(stringbuffer);
	/* here we log all the server traffic, prefix with timestamp */
	if(index(mystate->flags, (int)'l') != NULL) {
		fprintf(mystate->logfp, "%lu %s", (unsigned long) mystate->now, stringbuffer);
	}
	if((ptr = (char *) strstr(stringbuffer, "PING :")) != NULL) {
		snprintf(pong, STRINGLEN, "PONG :%s", ptr + 6);
#ifdef DEBUG
		oer_debug(OER_DEBUG_INFO, "handleserverdata->%s", pong);
#endif
		if(write(mystate->sockfd, pong, strlen(pong)) < 0) {
#ifdef DEBUG
			oer_debug(OER_DEBUG_ERROR, "handleserverdata->write failed: %s\n", strerror(errno));
#endif
			return OER_HANDLESERVERDATA_ERR_WRITE;
		}
		mystate->current_server->tx += strlen(pong);
	}
	else {
		/* everything else but pings */
		parseirc(stringbuffer);
	}
        return OER_HANDLESERVERDATA_EVERYTHING_OK;
}

int processtimeds()
{
	int got_timed;
	struct channel *this;
	struct timed *t1;
	struct timed *t2;
	char stringbuffer[WRITE_BUFFER_LENGTH + 1];
#ifdef DEBUG
        oer_debug(OER_DEBUG_NOISE, "processtimeds()\n");
#endif
	/* check if connected */
	if(mystate->current_server == NULL) {
		return OER_PROCESSTIMEDS_EVERYTHING_OK;
	}
	/* check if registered */
        if(!mystate->current_server->registered.done) {
                return OER_REGISTERCONNECTION_EVERYTHING_OK;
        }
	if(mystate->netjoining) {
		/* don't do any actions while net is joining */
		return OER_PROCESSTIMEDS_EVERYTHING_OK;
	}
	/* lower barrier */
	if(mystate->last_action.ts < mystate->now && mystate->last_action.barrier) {
		mystate->last_action.barrier--;
	}
        for(t1 = mystate->timeds; t1 != NULL; t1 = t2) {
		if(t1->at > mystate->now) {
			t2 = t1->next;
			continue;
		}
		/* check if timed can be scheduled now */
		if(!processactions(t1)) {
			return OER_PROCESSTIMEDS_EVERYTHING_OK;
		}
		got_timed = 0;
		switch(t1->type) {
		case OER_TIMED_TYPE_KICK:
			if((this = getchptr(t1->channel)) == NULL) {
				return OER_PROCESSTIMEDS_EVERYTHING_OK;
			}
			/* this check is necessary because KICK messages are
			   scheduled before executed and it is possible that
			   there was manual prevention (!unlock) */
			if(!this->locked.unlocked) {
				snprintf(stringbuffer, WRITE_BUFFER_LENGTH, "%s\n", t1->command);
				got_timed = 1;
			}
			break;
		case OER_TIMED_TYPE_NORMAL:
		case OER_TIMED_TYPE_USERHOST:
			snprintf(stringbuffer, WRITE_BUFFER_LENGTH, "%s\n", t1->command);
			got_timed = 1;
			break;
		}
		if(got_timed) {
#ifdef DEBUG
			oer_debug(OER_DEBUG_INFO, "processtimeds->%s", stringbuffer);
#endif
			if(write(mystate->sockfd, stringbuffer, strlen(stringbuffer)) < 0) {
#ifdef DEBUG
				oer_debug(OER_DEBUG_ERROR, "processtimeds->write failed: %s\n", strerror(errno));
#endif
				return OER_PROCESSTIMEDS_ERR_WRITE;
			}
			mystate->current_server->tx += strlen(stringbuffer);
		}
		t2 = t1->next;
		timed_del(t1);
		t1 = t2;
	}
	return OER_PROCESSTIMEDS_EVERYTHING_OK;
}

int processactions(struct timed *t)
{
	int delta;
	int weight;
	struct channel *this;

	delta = mystate->now - mystate->last_action.ts;
#ifdef DEBUG
	/* prevent initial flooding of the console */
	if((mystate->now - mystate->current_server->linkup) >= 10) {
		oer_debug(OER_DEBUG_NOISE, "processactions(\"%lu\")\n", t->at);
		oer_debug(OER_DEBUG_INFO, "processactions->last action at %lu / delta %d / barrier %d\n", mystate->last_action.ts, delta, mystate->last_action.barrier);
	}
#endif
	if((t->prio == OER_TIMED_PRIORITY_CHANNEL_HANDLING || t->prio == OER_TIMED_PRIORITY_CHANNEL_PROTECTION) && t->type != OER_TIMED_TYPE_KICK) {
		if(delta || mystate->last_action.barrier < 5) {
			mystate->last_action.ts = mystate->now;
			mystate->last_action.barrier += 1 + (strlen(t->command) / 50);
			return 1;
		}
	}
	if(mystate->last_action.barrier) {
		return 0;
	}
	mystate->last_action.ts = mystate->now;
	switch(t->prio) {
	case OER_TIMED_PRIORITY_WALL:
		if((this = getchptr(t->channel)) == NULL) {
			return 0;
		}
		/* this is necessary to avoid ERR_TARGETTOOFAST in ircu */
		mystate->last_action.barrier += 5 + (this->nickcount / 2) + (strlen(t->command) / 50);
		break;
	case OER_TIMED_PRIORITY_FLOOD:
		if(t->type == OER_TIMED_TYPE_USERHOST) {
			mystate->last_action.barrier += 2 + (strlen(t->command) / 50);
		} else {
			mystate->last_action.barrier += 3 + (strlen(t->command) / 50);
		}
		break;
	case OER_TIMED_PRIORITY_CTCP:
		/* this is a flood protection, somebody could flood an otherwise
		   idle oer by sending it ctcp queries in fixed intervals of 1..2
		   seconds, it all comes down to ircd's flood detection */
		weight = (delta) ? (2 / (delta + 1)) : 2;
		mystate->last_action.barrier += weight + 2 + (strlen(t->command) / 50);
		break;
	case OER_TIMED_PRIORITY_NOTICE:
	case OER_TIMED_PRIORITY_PRIVMSG:
		mystate->last_action.barrier += 1 + (strlen(t->command) / 50);
		break;
	case OER_TIMED_PRIORITY_NORMAL:
	case OER_TIMED_PRIORITY_CHANNEL_HANDLING:
	case OER_TIMED_PRIORITY_CHANNEL_PROTECTION:
		if(t->type == OER_TIMED_TYPE_KICK) {
			mystate->last_action.barrier += 2 + (strlen(t->command) / 50);
		} else {
			mystate->last_action.barrier += 1 + (strlen(t->command) / 50);
		}
		break;
	}
	return 1;
}
