/*
 * Send Message Function
 *
 * Original Author: zed@mentasm.com
 */
 
#include "datatype.h"
#include "gtkicq.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "tcp.h"
#include "sendmsg.h"
#include "msg_queue.h"

int search_wait;
ProgressData *search_pdata;

char *cr_convert( char *text );
void Wrinkle( void *ptr, size_t len );
static size_t SOCKWRITE_LOW( SOK_T sok, void * ptr, size_t len );

/****************************************************************
Checks if packets are waiting to be resent and sends them.
*****************************************************************/
void Do_Resend( SOK_T sok )
{
	struct msg *queued_msg;
	SIMPLE_MESSAGE_PTR s_mesg;
	DWORD type; 
	char *data;
	char *tmp;
	char *temp;
	char url_desc[1024], url_data[1024];
	net_icq_pak pak;

	if ((queued_msg = msg_queue_pop()) != NULL)
	{
		queued_msg->attempts++;
		if (queued_msg->attempts <= 6)
		{
			temp = malloc( queued_msg->len );
			memcpy( temp, queued_msg->body, queued_msg->len);
			SOCKWRITE_LOW(sok, temp, queued_msg->len);
			free(temp);
			queued_msg->exp_time = time(NULL) + 10; 
			msg_queue_push( queued_msg );
		}
		else
		{
			memcpy(&pak.head.ver, queued_msg->body, queued_msg->len);
/*
			if ( CMD_SENDM  == Chars_2_Word( pak.head.cmd ) )
			{
				s_mesg = ( SIMPLE_MESSAGE_PTR ) pak.data;
				M_print("\nDiscarding message to ");
				Print_UIN_Name( Chars_2_DW( s_mesg->uin ) );
				M_print(" after %d send attempts.  Message content:\n",
				        queued_msg->attempts - 1);

				type = Chars_2_Word(s_mesg->type);
				data = s_mesg->len + 2; 
				if (type == URL_MESS || type == MRURL_MESS)
				{
					tmp = strchr( data, '\xFE' );
					if ( tmp != NULL )
					{
						*tmp = 0;
						rus_conv("wk", data);
						strcpy(url_desc, data);
						tmp++;
						data = tmp;
						rus_conv("wk", data);
						strcpy(url_data, data);

						M_print( " Description: " MESSCOL "%s" \
						        NOCOL "\n", url_desc );
						M_print( " URL        : " MESSCOL "%s" NOCOL "\n", 
						        url_data );
					}
				}
				else if (type == NORM_MESS || type == MRNORM_MESS)
				{
					rus_conv("wk", data); 
					M_print( MESSCOL "%s", data );
					M_print( NOCOL "\n" );
				}
			}
			else
			{
				M_print( "\nDiscarded a " );
				Print_CMD( Chars_2_Word( pak.head.cmd ) );
				M_print( " packet.\n" );
				if( ( CMD_LOGIN == Chars_2_Word( pak.head.cmd ) ) ||
				    ( CMD_KEEP_ALIVE == Chars_2_Word( pak.head.cmd ) ) )
				{
					M_print( "\aConnection unstable exiting....\n" );
					Quit = TRUE;
				}
			}
*/
			free(queued_msg->body);
			free(queued_msg);
		}

		if ( (queued_msg = msg_queue_peek() ) != NULL )
		{
			next_resend = queued_msg->exp_time; 
		}
		else
		{
			next_resend = INT_MAX;
		}
	}
	else
   {
		next_resend = INT_MAX;
	}
}


/********************************************************
The following data constitutes fair use for compatibility.
*********************************************************/
unsigned char icq_check_data[257] = {
   0x0a, 0x5b, 0x31, 0x5d, 0x20, 0x59, 0x6f, 0x75,
   0x20, 0x63, 0x61, 0x6e, 0x20, 0x6d, 0x6f, 0x64,
   0x69, 0x66, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20,
   0x73, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x20, 0x49,
   0x43, 0x51, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x73,
   0x2e, 0x20, 0x4a, 0x75, 0x73, 0x74, 0x20, 0x73,
   0x65, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x22, 0x53,
   0x6f, 0x75, 0x6e, 0x64, 0x73, 0x22, 0x20, 0x66,
   0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20,
   0x22, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65,
   0x6e, 0x63, 0x65, 0x73, 0x2f, 0x6d, 0x69, 0x73,
   0x63, 0x22, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x43,
   0x51, 0x20, 0x6f, 0x72, 0x20, 0x66, 0x72, 0x6f,
   0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x22, 0x53,
   0x6f, 0x75, 0x6e, 0x64, 0x73, 0x22, 0x20, 0x69,
   0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f,
   0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x70, 0x61,
   0x6e, 0x65, 0x6c, 0x2e, 0x20, 0x43, 0x72, 0x65,
   0x64, 0x69, 0x74, 0x3a, 0x20, 0x45, 0x72, 0x61,
   0x6e, 0x0a, 0x5b, 0x32, 0x5d, 0x20, 0x43, 0x61,
   0x6e, 0x27, 0x74, 0x20, 0x72, 0x65, 0x6d, 0x65,
   0x6d, 0x62, 0x65, 0x72, 0x20, 0x77, 0x68, 0x61,
   0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x61,
   0x69, 0x64, 0x3f, 0x20, 0x20, 0x44, 0x6f, 0x75,
   0x62, 0x6c, 0x65, 0x2d, 0x63, 0x6c, 0x69, 0x63,
   0x6b, 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x20, 0x75,
   0x73, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x67,
   0x65, 0x74, 0x20, 0x61, 0x20, 0x64, 0x69, 0x61,
   0x6c, 0x6f, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x61,
   0x6c, 0x6c, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61,
   0x67, 0x65, 0x73, 0x20, 0x73, 0x65, 0x6e, 0x74,
   0x20, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0
};


char *cr_convert( char *text )
{
	char *t;
	int cx, cy;
	
	cy = 0;
	for( cx = 0; cx < strlen( text ); cx ++ )
	{
		if( text[ cx ] == '\n' )
			cy ++;
	}
	
	t = malloc( strlen( text ) + cy + 1 );

	cy = 0;
	for( cx = 0; cx < strlen( text ); cx ++ )
	{
		if( text[ cx ] != '\n' )
			t[ cy ++ ] = text[ cx ];
		else
		{
			t[ cy ++ ] = '\r';
			t[ cy ++ ] = '\n';
		}
	}

	t[ cy ] = 0x00;
	
	return t;
}

/*
 * Send a message thru the Server to the UIN
 * 'text' is the message
 */
void icq_sendmsg( SOK_T sok, DWORD uin, char *text, struct sokandlb *data, int forced )
{
	SIMPLE_MESSAGE msg;
	net_icq_pak pak;
	int size, len; 
	char *new_text;

#ifdef TRACE_FUNCTION
	printf( "icq_sendmsg\n" );
#endif

	if( strlen( text ) == 0 )
	{
		OK_Box( "Cannot send blank message", "" );
		return;
	}

	new_text = cr_convert( text );

	/* Add statement to personal history file */
	add_outgoing_to_history( uin, new_text );

	if( !forced && !force_toggle && TCPSendMessage( uin, new_text, data ) )
	{
		log_window_add( "Sent Message (TCP)", 1, uin );
		return;
	}

	log_window_add( "Sent Message (UDP)", 1, uin );
	rus_conv ("kw",new_text);
	

	len = strlen(new_text);
	Word_2_Chars( pak.head.ver, ICQ_VER );
	Word_2_Chars( pak.head.cmd, CMD_SENDM );
	Word_2_Chars( pak.head.seq, seq_num++ );
	DW_2_Chars( pak.head.UIN, UIN );

	DW_2_Chars( msg.uin, uin );
	DW_2_Chars(msg.type, 0x0001 );		/* A type 1 msg*/
	Word_2_Chars( msg.len, len + 1 );	/* length + the NULL */

	memcpy(&pak.data, &msg, sizeof( msg ) );
	memcpy(&pak.data[8], new_text, len + 1);

	size = sizeof( msg ) + len + 1;

/*
	packet_print( (pak.head.ver), size + sizeof( pak.head ) - 2,
	              PACKET_TYPE_UDP | PACKET_DIRECTION_SEND );
*/
	last_cmd[seq_num - 1 ] = Chars_2_Word( pak.head.cmd );
	SOCKWRITE( sok, &(pak.head.ver), size + sizeof( pak.head ) - 2);

	free( new_text );
}

void icq_sendurl( GtkWidget *widget, struct URLInfo *data )
{
	SIMPLE_MESSAGE msg;
	net_icq_pak pak;
	int size, len; 
	int uin;
	char *new_text;
	char *buf;
	char *text;

#ifdef TRACE_FUNCTION
	printf( "icq_sendurl\n" );
#endif

	uin = Contacts[ data->cindex ].uin;
	
	len = strlen( gtk_entry_get_text( GTK_ENTRY( data->url ) ) ) +
	      strlen( gtk_entry_get_text( GTK_ENTRY( data->desc ) ) ) + 2;

	text = (char *)malloc( len );
	sprintf( text, "%s\xFE%s", gtk_entry_get_text( GTK_ENTRY( data->desc ) ),
	         gtk_entry_get_text( GTK_ENTRY( data->url ) ) );

	new_text = cr_convert( text );
	buf = (char *)malloc( sizeof( char ) * ( 16 + strlen( new_text ) ) );

	/* Add statement to personal history file */
	add_outgoing_to_history( uin, new_text );

	if( TCPSendURL( uin, new_text, data->data ) )
	{
		sprintf( buf, "Sent URL (TCP)" );
		log_window_add( buf, 1, uin );
		free( buf );
		free( new_text );
		return;
	}

	sprintf( buf, "Sent URL (UDP)" );
	log_window_add( buf, 1, uin );
	free( buf );
	rus_conv ("kw",new_text);
	
	len = strlen(new_text);
	Word_2_Chars( pak.head.ver, ICQ_VER );
	Word_2_Chars( pak.head.cmd, CMD_SENDM );
	Word_2_Chars( pak.head.seq, seq_num++ );
	DW_2_Chars( pak.head.UIN, UIN );

	DW_2_Chars( msg.uin, uin );
	DW_2_Chars(msg.type, 0x0004 );		/* A type 4 msg*/
	Word_2_Chars( msg.len, len + 1 );	/* length + the NULL */

	memcpy(&pak.data, &msg, sizeof( msg ) );
	memcpy(&pak.data[8], new_text, len + 1);

	size = sizeof( msg ) + len + 1;

/*
	packet_print( (pak.head.ver), size + sizeof( pak.head ) - 2,
	              PACKET_TYPE_UDP | PACKET_DIRECTION_SEND );
*/
	last_cmd[seq_num - 1 ] = Chars_2_Word( pak.head.cmd );
	SOCKWRITE( data->data->sok, &(pak.head.ver), size + sizeof( pak.head ) - 2);

	free( new_text );
}

/*
 * Send an authorization to the server so the
 * client can add the user
 */
void icq_sendauthmsg( SOK_T sok, DWORD uin)
{
	SIMPLE_MESSAGE msg;
	net_icq_pak pak;
	int size; 

#ifdef TRACE_FUNCTION
	printf( "icq_sendauthmsg\n" );
#endif

	Word_2_Chars( pak.head.ver, ICQ_VER );
	Word_2_Chars( pak.head.cmd, CMD_SENDM );
	Word_2_Chars( pak.head.seq, seq_num++ );
	DW_2_Chars( pak.head.UIN, UIN );

	DW_2_Chars( msg.uin, uin );
	DW_2_Chars( msg.type, AUTH_MESSAGE );		/* A type authorization msg*/
	Word_2_Chars( msg.len, 2 );		

	memcpy(&pak.data, &msg, sizeof( msg ) );

	pak.data[ sizeof(msg) ]=0x03;
	pak.data[ sizeof(msg) + 1]=0x00;

	size = sizeof( msg ) + 2;

/*
	packet_print( (pak.head.ver), size + sizeof( pak.head ) - 2,
	              PACKET_TYPE_UDP | PACKET_DIRECTION_SEND );
*/
	last_cmd[seq_num - 1 ] = Chars_2_Word( pak.head.cmd );
	SOCKWRITE( sok, &(pak.head.ver), size + sizeof( pak.head ) - 2);
}

/* Change User Status */
void icq_change_status( SOK_T sok, DWORD status, struct sokandlb *data )
{
	net_icq_pak pak;
	int size ;

#ifdef TRACE_FUNCTION
	printf( "icq_change_status\n" );
#endif

	Word_2_Chars( pak.head.ver, ICQ_VER );
	Word_2_Chars( pak.head.cmd, CMD_STATUS_CHANGE );
	Word_2_Chars( pak.head.seq, seq_num++ );
	DW_2_Chars( pak.head.UIN, UIN );

	DW_2_Chars( pak.data, ( status | 0x10000 ) );
	Current_Status = status;

	size = 4;

/*
	packet_print( (pak.head.ver), size + sizeof( pak.head ) - 2,
	              PACKET_TYPE_UDP | PACKET_DIRECTION_SEND );
*/
	last_cmd[seq_num - 1 ] = Chars_2_Word( pak.head.cmd );
	SOCKWRITE( sok, &(pak.head.ver), size + sizeof( pak.head ) - 2);

	ready_set();

}

/* Disconnect from ICQ server */
void Quit_ICQ( int sok )
{
	net_icq_pak pak;
	int size, len;

#ifdef TRACE_FUNCTION
	printf( "Quit_ICQ\n" );
#endif
   
	Word_2_Chars( pak.head.ver, ICQ_VER );
	Word_2_Chars( pak.head.cmd, CMD_SEND_TEXT_CODE );
	Word_2_Chars( pak.head.seq, seq_num++ );
	DW_2_Chars( pak.head.UIN, UIN );
   
	len = strlen( "B_USER_DISCONNECTED" ) + 1;
	*(short * ) pak.data = len;
	size = len + 4;
   
	memcpy( &pak.data[2], "B_USER_DISCONNECTED", len );
	pak.data[ 2 + len ] = 05;
	pak.data[ 3 + len ] = 00;

/*
	packet_print( (pak.head.ver), size + sizeof( pak.head ) - 2,
	              PACKET_TYPE_UDP | PACKET_DIRECTION_SEND );
*/
	last_cmd[seq_num - 1 ] = Chars_2_Word( pak.head.cmd );
	SOCKWRITE( sok, &(pak.head.ver), size + sizeof( pak.head ) - 2);

	SOCKCLOSE(sok);
	SOCKCLOSE( sok );
}

/* Send a request for Info on a User */
void send_info_req( SOK_T sok, DWORD uin )
{
	net_icq_pak pak;
	int size ;

#ifdef TRACE_FUNCTION
	printf( "send_info_req\n" );
#endif

	Word_2_Chars( pak.head.ver, ICQ_VER );
	Word_2_Chars( pak.head.cmd, CMD_INFO_REQ );
	Word_2_Chars( pak.head.seq, seq_num++ );
	DW_2_Chars( pak.head.UIN, UIN );

	DW_2_Chars( pak.data, uin );

	size = 4;

/*
	packet_print( (pak.head.ver), size + sizeof( pak.head ) - 2,
	              PACKET_TYPE_UDP | PACKET_DIRECTION_SEND ); 
*/
	last_cmd[seq_num - 1 ] = Chars_2_Word( pak.head.cmd );
	SOCKWRITE( sok, &(pak.head.ver), size + sizeof( pak.head ) - 2);
}

/* Start a Server Search for Information Specified */
void start_search( SOK_T sok, char *email, char *nick, char* first, char* last, DWORD uin )
{
	net_icq_pak pak;
	int size;

#ifdef TRACE_FUNCTION
	printf( "start_search\n" );
#endif

	if( uin > 0 )
	{
		show_info_new( sok, uin );
		return;
	}

	search_wait = show_wait( "Search in Progress", search_pdata );
	gtk_statusbar_push( GTK_STATUSBAR( statusbar ), 2 + search_wait,
	                    " Search in Progress..." );

	Word_2_Chars( pak.head.ver, ICQ_VER );
	Word_2_Chars( pak.head.cmd, CMD_SEARCH_USER );
	Word_2_Chars( pak.head.seq, seq_num++ );
	DW_2_Chars( pak.head.UIN, UIN );

/*
	Word_2_Chars( pak.data , seq_num++ );
	size = 2;
*/
	size = 0;
	Word_2_Chars( pak.data + size, strlen( nick ) + 1 );
	size += 2;
	strcpy( pak.data + size , nick );
	size += strlen( nick ) + 1;
	Word_2_Chars( pak.data + size, strlen( first ) + 1 );
	size += 2;
	strcpy( pak.data + size , first );
	size += strlen( first ) + 1;
	Word_2_Chars( pak.data + size, strlen( last ) + 1);
	size += 2;
	strcpy( pak.data + size , last );
	size += strlen( last ) +1 ;
	Word_2_Chars( pak.data + size, strlen( email ) + 1  );
	size += 2;
	strcpy( pak.data + size , email );
	size += strlen( email ) + 1;
	last_cmd[seq_num - 2 ] = Chars_2_Word( pak.head.cmd );
/*
	packet_print( (pak.head.ver), size + sizeof( pak.head ) - 2,
	              PACKET_TYPE_UDP | PACKET_DIRECTION_SEND );
*/
	SOCKWRITE( sok, &(pak.head.ver), size + sizeof( pak.head ) - 2);
}

void send_ext_info_req( SOK_T sok, DWORD uin )
{
	net_icq_pak pak;
	int size ;

#ifdef TRACE_FUNCTION
	printf( "send_ext_info_req\n" );
#endif

	Word_2_Chars( pak.head.ver, ICQ_VER );
	Word_2_Chars( pak.head.cmd, CMD_EXT_INFO_REQ );
	Word_2_Chars( pak.head.seq, seq_num++ );
	DW_2_Chars( pak.head.UIN, UIN );

	DW_2_Chars( pak.data, uin );
	size = 4;

/*
	packet_print( (pak.head.ver), size + sizeof( pak.head ) - 2,
	              PACKET_TYPE_UDP | PACKET_DIRECTION_SEND );
*/
	last_cmd[seq_num - 2 ] = Chars_2_Word( pak.head.cmd );
	SOCKWRITE( sok, &(pak.head.ver), size + sizeof( pak.head ) - 2);
}

void reg_new_user( SOK_T sok, char *pass)
{
	net_icq_pak pak;
	char len_buf[2];
	int size, len;

#ifdef TRACE_FUNCTION
	printf( "reg_new_user\n" );
#endif

	len = strlen( pass );
	Word_2_Chars( pak.head.ver, ICQ_VER );
	Word_2_Chars( pak.head.cmd, CMD_REG_NEW_USER );
	Word_2_Chars( pak.head.seq, seq_num ++ );
	Word_2_Chars( pak.head.seq2, seq_num - 1 );
	Word_2_Chars( len_buf, len );

   memcpy(&pak.data[0], len_buf, 2 );
   memcpy(&pak.data[2], pass, len + 1);
   DW_2_Chars( &pak.data[2+len], 0xA0 );
   DW_2_Chars( &pak.data[6+len], 0x2461 );
   DW_2_Chars( &pak.data[10+len], 0xa00000 );
   DW_2_Chars( &pak.data[14+len], 0x00 );
   size = len + 18;

	last_cmd[seq_num - 1 ] = Chars_2_Word( pak.head.cmd );
/*
	packet_print( (pak.head.ver), size + sizeof( pak.head ) - 2,
	              PACKET_TYPE_UDP | PACKET_DIRECTION_SEND );
*/
	SOCKWRITE_LOW( sok, &( pak.head.ver ), size + sizeof( pak.head ) - 2);
}

void Update_User_Info( SOK_T sok, USER_INFO_PTR user)
{
	net_icq_pak pak;
	int size ;

#ifdef TRACE_FUNCTION
	printf( "Update_User_Info\n" );
#endif

	Word_2_Chars( pak.head.ver, ICQ_VER );
	if( is_new_user )
		Word_2_Chars( pak.head.cmd, CMD_NEW_USER_INFO );
	else
		Word_2_Chars( pak.head.cmd, CMD_UPDATE_INFO );
	Word_2_Chars( pak.head.seq, seq_num++ );
	DW_2_Chars( pak.head.UIN, UIN );

	size = 0;

   Word_2_Chars( pak.data + size, strlen( user->nick ) + 1 );
   size += 2;
   strcpy( pak.data + size , user->nick );
   size += strlen( user->nick ) + 1;
   Word_2_Chars( pak.data + size, strlen( user->first ) + 1 );
   size += 2;
   strcpy( pak.data + size , user->first );
   size += strlen( user->first ) + 1;
   Word_2_Chars( pak.data + size, strlen( user->last ) + 1);
   size += 2;
   strcpy( pak.data + size , user->last );
   size += strlen( user->last ) +1 ;
   Word_2_Chars( pak.data + size, strlen( user->email ) + 1  );
   size += 2;
   strcpy( pak.data + size , user->email );
   size += strlen( user->email ) + 1;
   pak.data[ size ] = user->auth;
   size++;
/*
	packet_print( (BYTE *)&(pak.head.ver), size + sizeof( pak.head ) - 2,
	               PACKET_TYPE_UDP | PACKET_DIRECTION_SEND );
*/
	last_cmd[ ( seq_num - 1 ) & 0x3ff ] = Chars_2_Word( pak.head.cmd );
	SOCKWRITE( sok, ( char * )&(pak.head.ver), size + sizeof( pak.head ) - 2);
}

void Wrinkle( void *ptr, size_t len )
{
	static BOOL before = FALSE;
	BYTE *buf;
	DWORD chksum;
	DWORD key;
	DWORD tkey, temp;
	BYTE r1, r2;
	int n, pos;
	DWORD chk1, chk2;
	
	buf = ptr;

	if( !before )
		srand( time( NULL ) );
	
	buf[2] = rand() & 0xff;
	buf[3] = rand() & 0xff;
	buf[4] = 0;
	buf[5] = 0;
	
	r1 = rand() % ( len - 4 );
	r2 = rand() & 0xff;
	
	chk1 = (BYTE) buf[8];
	chk1 <<= 8;
	chk1 += (BYTE) buf[4];
	chk1 <<= 8;
	chk1 += (BYTE) buf[2];
	chk1 <<= 8;
	chk1 += (BYTE) buf[6];
	chk2 = r1;
	chk2 <<= 8;
	chk2 += (BYTE) ( buf[ r1 ] );
	chk2 <<= 8;
	chk2 += r2;
	chk2 <<= 8;
	chk2 += (BYTE) ( icq_check_data[ r2 ] );
	chk2 ^= 0x00ff00ff;
	
	chksum = chk2 ^ chk1;
	
	DW_2_Chars( &buf[ 0x10 ], chksum );
	key = len;
	key *= 0x66756B65;
	key += chksum;
	n = ( len + 3 ) / 4;
	pos = 0;
	while( pos < n )
	{
		if( pos != 0x10 )
		{
			tkey = key + icq_check_data[ pos & 0xff ];
			temp = Chars_2_DW( &buf[ pos ] );
			temp ^= tkey;
			DW_2_Chars( &buf[ pos ], temp );
		}
		pos += 4;
	}
	Word_2_Chars( &buf[ 0 ], ICQ_VER );
}

/***************************************************************
This handles actually sending a packet after it's been assembled.
When V5 is implemented this will wrinkle the packet and calculate 
the checkcode.
Adds packet to the queued messages.
****************************************************************/
size_t SOCKWRITE( SOK_T sok, void * ptr, size_t len )
{
   struct msg *msg_to_queue;
   WORD cmd;

   Word_2_Chars( &((BYTE *)ptr)[4], 0 );
   ((BYTE *)ptr)[0x0A] = ((BYTE *) ptr)[8];
   ((BYTE *)ptr)[0x0B] = ((BYTE *) ptr)[9];

   cmd = Chars_2_Word( (((ICQ_PAK_PTR)((BYTE*)ptr-2))->cmd ) );
   if ( cmd != CMD_ACK ) {
      msg_to_queue = (struct msg *) malloc(sizeof(struct msg));
      msg_to_queue->seq = Chars_2_Word( &((BYTE *)ptr)[0x0A] );
      msg_to_queue->attempts = 1;
      msg_to_queue->exp_time = time(NULL) + 10;
      msg_to_queue->body = (char *) malloc( len );
      msg_to_queue->len = len;
      memcpy(msg_to_queue->body, ptr, msg_to_queue->len);
      msg_queue_push( msg_to_queue );

      if (msg_queue_peek() == msg_to_queue)
      {
	  next_resend = msg_to_queue->exp_time;
      }
   }

   return SOCKWRITE_LOW( sok, ptr, len );
}


/***************************************************************
This handles actually sending a packet after it's been assembled.
When V5 is implemented this will wrinkle the packet and calculate
the checkcode.
****************************************************************/
size_t SOCKWRITE_LOW( int sok, void * ptr, size_t len )
{
	int retval;

	if( Connected )
	 	packet_print( ptr, len, PACKET_TYPE_UDP | PACKET_DIRECTION_SEND );

#ifdef TRACE_FUNCTION
	printf( "SOCKWRITE\n" );
#endif

   Wrinkle( ptr, len );

	if( Connected && MainData->sok > 0 )
	   retval = sockwrite( sok, ptr, len );
	else
		retval = FALSE;

	/* -1 means we have a problem, so figure we're not connected */
/*
	if( retval == -1 && Done_Login )
	{
		icq_set_status_offline( NULL, MainData );
	}
*/
	return retval; 
}

size_t SOCKREAD( SOK_T sok, void * ptr, size_t len )
{
   size_t sz;

#ifdef TRACE_FUNCTION
	printf( "SOCKREAD\n" );
#endif

   sz = sockread( sok, ptr, len );
   return sz;
}
