/************************************************************************
 *   IRC - Internet Relay Chat, src/packet.c
 *   Copyright (C) 1990  Jarkko Oikarinen and
 *                       University of Oulu, Computing Center
 *
 *   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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* $Id: packet.c,v 1.2 2006/01/07 22:13:26 trystanscott Exp $ */

#include "struct.h"
#include "common.h"
#include "sys.h"
#include "msg.h"
#include "h.h"
#include "dh.h"
#include "zlink.h"

/*
 * * dopacket 
 * cptr - pointer to client structure for which the buffer
 * data applies. 
 * buffer - pointr to the buffer containing the newly read data 
 * length - number of valid bytes of data in the buffer
 * 
 * Note: 
 * It is implicitly assumed that dopacket is called only
 * with cptr of "local" variation, which contains all the
 * necessary fields (buffer etc..)
 */
int dopacket(aClient *cptr, char *buffer, int length)
{
    char   *ch1;
    char   *ch2;
    char *cptrbuf = cptr->buffer;
    aListener    *lptr = cptr->lstn;
    char *nbuf = NULL;
    int nlen;
    
#ifdef HAVE_ENCRYPTION_ON
    if(IsRC4IN(cptr))
	rc4_process_stream(cptr->serv->rc4_in, (unsigned char *) buffer, length);
#endif
    
    me.receiveB += length;	   /* Update bytes received */
    cptr->receiveB += length;
    
    if (cptr->receiveB & 0x0400) 
    {
	cptr->receiveK += (cptr->receiveB >> 10);
	cptr->receiveB &= 0x03ff;  /* 2^10 = 1024, 3ff = 1023 */
    }

    if (lptr) 
    {
	lptr->receiveB += length;
	if (lptr->receiveB & 0x0400)
	{
	    lptr->receiveK += (lptr->receiveB >> 10);
	    lptr->receiveB &= 0x03ff;
	}
    }
    else if (me.receiveB & 0x0400)
    {
	me.receiveK += (me.receiveB >> 10);
	me.receiveB &= 0x03ff;
    }
    
zcontinue:
    ch1 = cptrbuf + cptr->count;
    ch2 = buffer;   
    
    if(ZipIn(cptr))
    {
	int err;
	ch2 = zip_input(cptr->serv->zip_in, ch2, &length, &err, &nbuf, &nlen);

	if(length == -1)
	{
	    sendto_realops("Zipin error for %s: (%d) %s\n", cptr->name,
			   err, ch2);
	    return exit_client(cptr, cptr, &me, "fatal error in zip_input!");
	}
    }
    
    while (--length >= 0) 
    {
	char g;
	
	g = (*ch1 = *ch2++);
	/*
	 * Yuck.  Stuck.  To make sure we stay backward compatible, we
	 * must assume that either CR or LF terminates the message and
	 * not CR-LF.  By allowing CR or LF (alone) into the body of
	 * messages, backward compatibility is lost and major problems
	 * will arise. - Avalon
	 */
	if (g < '\16' && (g == '\n' || g == '\r')) {
	    if (ch1 == cptrbuf)
		continue;		/* Skip extra LF/CR's */
	    *ch1 = '\0';
	    me.receiveM += 1;	/* Update messages received */
	    cptr->receiveM += 1;
	    if (lptr)
		lptr->receiveM += 1;
	    cptr->count = 0;	/*
				 * ...just in case parse returns with
				 * FLUSH_BUFFER without removing the
				 * structure pointed by cptr... --msa 
				 */
	    switch (parse(cptr, cptr->buffer, ch1))
	    {
	    case FLUSH_BUFFER:
		return FLUSH_BUFFER;
		
	    case ZIP_NEXT_BUFFER:
		if(length)
		{
		    int err;
		    ch2 = zip_input(cptr->serv->zip_in, ch2, &length,
				    &err, &nbuf, &nlen);
		    
		    if(length == -1)
		    {
			sendto_realops("Zipin error for %s: (%d) %s\n",
				       cptr->name, err, ch2);
			return exit_client(cptr, cptr, &me,
					   "fatal error in zip_input!");
		    }
		}
		break;

#ifdef HAVE_ENCRYPTION_ON
	    case RC4_NEXT_BUFFER:
		if(length)
		    rc4_process_stream(cptr->serv->rc4_in, (unsigned char *) ch2, length);
		break;
#endif

	    default:
		break;
	    }
	    
	    /*
	     * Socket is dead so exit (which always returns with *
	     * FLUSH_BUFFER here).  - avalon
	     */
	    if (cptr->flags & FLAGS_DEADSOCKET)
		return exit_client(cptr, cptr, &me,
				   (cptr->flags & FLAGS_SENDQEX) ?
				   "SendQ exceeded" : "Dead socket");
	    ch1 = cptrbuf;
	}
	else if (ch1 < cptrbuf + (sizeof(cptr->buffer) - 1))
	    ch1++;			/* There is always room for the null */
    }
    cptr->count = ch1 - cptrbuf;
    
    if(nbuf)
    {
#if 0   /* this message is annoying and not quite that useful */
	static time_t last_complain = 0;
	static int numrepeat = 0;
	
	numrepeat++;
	
	if(NOW > (last_complain + 300)) /* if more than 5 mins have elapsed */
	{
	    if(last_complain == 0)
	    {
		sendto_realops("Overflowed zipInBuf! "
			       "If you see this a lot, you should increase "
			       "zipInBufSize in src/zlink.c.");
	    }
	    else
	    {
		sendto_realops("Overflowed zipInBuf %d time%s in the "
			       "last %d minutes. If you see this a lot, you "
			       "should increase zipInBufSize in src/zlink.c.",
			       numrepeat, numrepeat == 1 ? "" : "s",
			       (NOW - last_complain) / 60);
	    }
	    last_complain = NOW;
	    numrepeat = 0;
	}
#endif

	buffer = nbuf;
	length = nlen;
	nbuf = NULL;
	goto zcontinue; /* gross, but it should work.. */
    }   
    
    return 0;
}

int client_dopacket(aClient *cptr, char *buffer, int length)
{
    
    strncpy(cptr->buffer, buffer, BUFSIZE);
    length = strlen(cptr->buffer);
    
    /* Update messages received */
    ++me.receiveM;
    ++cptr->receiveM;
   
    /* Update bytes received */
    cptr->receiveB += length;
   
    if (cptr->receiveB > 1023)
    {
	cptr->receiveK += (cptr->receiveB >> 10);
	cptr->receiveB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */
    }
    me.receiveB += length;
    
    if (me.receiveB > 1023)
    {
	me.receiveK += (me.receiveB >> 10);
	me.receiveB &= 0x03ff;
    }
    
    cptr->count = 0;    /* ...just in case parse returns with */
    if (FLUSH_BUFFER == parse(cptr, cptr->buffer, cptr->buffer + length))
    {
	/*
	 * CLIENT_EXITED means actually that cptr
	 * structure *does* not exist anymore!!! --msa
	 */
	return FLUSH_BUFFER;
    }
    else if (cptr->flags & FLAGS_DEADSOCKET)
    {
	/*
	 * Socket is dead so exit (which always returns with
	 * CLIENT_EXITED here).  - avalon
	 */
	return exit_client(cptr, cptr, &me,
			   (cptr->flags & FLAGS_SENDQEX) ?
			   "SendQ exceeded" : "Dead socket");
    }
    return 1;
}


syntax highlighted by Code2HTML, v. 0.9.1