#include "micq.h"
#include "datatype.h"
#include <stdio.h>
#include <stdlib.h>

#ifdef _WIN32
#include <conio.h>
#include <io.h>
#include <winsock2.h>
#include <time.h>
#else
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/wait.h>
#endif
#include <fcntl.h>
#include <time.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>

extern BOOL serv_mess[ 1024 ]; /* used so that we don't get duplicate messages with the same SEQ */

static void Multi_Packet( SOK_T sok, BYTE *data )
{
   int num_pack, i;
   int len;
   BYTE * j;
   srv_net_icq_pak pak;
   num_pack = (unsigned char) data[0];
   j = data;
   j++;
   
   for ( i=0; i < num_pack; i++ )
   {
       len = Chars_2_Word( j );
       pak = *( srv_net_icq_pak *) j ;
       j += 2;
#if 0
       M_print( "\nPacket Number %d\n", i );
       M_print( "Length %04X\n", len );
       M_print( "Command %04X\n", Chars_2_Word( pak.head.cmd ) );
       M_print( "SEQ %04X\n", Chars_2_Word( pak.head.seq ) );
       M_print( "Ver %04X\n", Chars_2_Word( pak.head.ver ) );
#endif
       Server_Response( sok, pak.data, len - sizeof( pak.head ), Chars_2_Word( pak.head.cmd ),
                 Chars_2_Word( pak.head.ver ), Chars_2_Word( pak.head.seq )
                 , Chars_2_Word( pak.head.UIN ) );
       j += len;
   }
}

void Server_Response( SOK_T sok, BYTE *data, DWORD len, WORD cmd, WORD ver, WORD seq, DWORD uin )
{
   SIMPLE_MESSAGE_PTR s_mesg;
   int i;
   
   switch ( cmd )
   {
   case SRV_ACK:
      if ( Verbose )
      {
         M_print( "\nThe server acknowledged the %04x command.\n", 
            last_cmd[ seq  ] );
         M_print( "The SEQ was %04X\n", seq );
      }
      break;
   case SRV_MULTI_PACKET:
/*      printf( "\n" );
      Hex_Dump( data, len );*/
      Multi_Packet( sok, data );
      break;
   case SRV_NEW_UIN:
      M_print( "\nThe new UIN is %ld!\n", uin );
      break;
   case SRV_UPDATE_FAIL:
      M_print( "\nFailed to update info.\n" );
      Prompt();
      break;
   case SRV_UPDATE_SUCCESS:
      M_print( "\nUser info successfully updated.\n" );
      Prompt();
      break;      
   case SRV_LOGIN_REPLY:
/*      UIN = Chars_2_DW( &pak.data[0] ); */
      our_ip = Chars_2_DW( &data[0] );
      M_print( "\nLogin successful! UIN : %lu\n", uin );
#if ICQ_VER == 0x0002
      M_print( " IP : %u.%u.%u.%u\t", data[4], data[5], data[6], data[7] );
#else
      M_print( " IP : %u.%u.%u.%u\t", data[0], data[1], data[2], data[3] );
#endif
      Time_Stamp();
      M_print( "\n" );
      snd_login_1( sok );
      snd_invis_list( sok );
      snd_vis_list( sok );
      snd_contact_list( sok );
/*      icq_change_status( sok, set_status );*/
      Prompt();
      break;
   case SRV_RECV_MESSAGE:
         Recv_Message( sok, data );
      Prompt();
      break;
   case SRV_X1: /* unknown message  sent after login*/
      if ( Verbose )
         M_print( "\nAcknowleged SRV_X1 0x021C Begin messages?\n" );
      break;
   case SRV_X2: /* unknown message  sent after login*/
      if ( Verbose )
         M_print( "\nAcknowleged SRV_X2 0x00E6 Done old messages?\n" );
      Show_Quick_Status();
      Done_Login = TRUE;
      snd_got_messages( sok );
      Prompt();
      break;
   case SRV_INFO_REPLY:
      Display_Info_Reply( sok, data );
      Prompt();
      break;
   case SRV_EXT_INFO_REPLY:
      Display_Ext_Info_Reply( sok, data );
      Prompt();
      break;
   case SRV_USER_OFFLINE:
      User_Offline( sok, data );
      Prompt();
      break;
   case SRV_BAD_PASS:
      M_print( MESSCOL "\nYou entered an incorrect password." NOCOL "\n" );
      exit( 1 );
      break;
   case SRV_TRY_AGAIN:
      M_print( MESSCOL "\nServer is busy please try again.\nTrying again...\n");
      Prompt();
#ifdef UNIX
      if ( fork() == 0 )
      {
         sleep( 5 );
         Login( sok, UIN, &passwd[0], our_ip, our_port, set_status );
         exit( 0 );
      }
#else
      Login( sok, UIN, &passwd[0], our_ip, our_port, set_status );
#endif
      for ( i = 0; i< 1024; i++ )
      {
         serv_mess[ i ]=FALSE;
      }
     break;
   case SRV_USER_ONLINE:
      User_Online( sok, data );
      Prompt();
      break;
   case SRV_STATUS_UPDATE:
      Status_Update( sok, data );
      Prompt();
      break;
   case SRV_GO_AWAY:
      #ifdef FUNNY_MSGS 
      M_print( "\nServer sent \"Go away!!\" command.\t" );
      #else
      M_print( "\nServer has forced us to disconnect.  This may be because of network lag.\t" );
      #endif
      Time_Stamp();
      Quit = TRUE;
      Prompt();
      break;
   case SRV_END_OF_SEARCH:
      M_print( "\nSearch done.\n" );
      Prompt();
      break;
   case SRV_USER_FOUND:
      Display_Search_Reply( sok, data );
      Prompt();
      break;
   case SRV_SYS_DELIVERED_MESS:
      M_print( "\n" );
      s_mesg = ( SIMPLE_MESSAGE_PTR ) data;
      last_recv_uin = Chars_2_DW( s_mesg->uin );
      Print_UIN_Name( Chars_2_DW( s_mesg->uin  ) );
      M_print( " - Instant Message\a " );
      if ( Verbose )
         M_print( " Type = %04x\t", Chars_2_Word( s_mesg->type ) );
      Time_Stamp();
      Do_Msg( sok, Chars_2_Word( s_mesg->type ), Chars_2_Word( s_mesg->len ), 
           s_mesg->len + 2,last_recv_uin); 
      if ( 0xfe != *( ((unsigned char *) s_mesg ) + sizeof( s_mesg ) ) )
      {
         if ( auto_resp &&
				(Current_Status != STATUS_ONLINE) &&
				(Current_Status != STATUS_FREE_CHAT)  )
         {
				switch ( Current_Status )
				{
				case STATUS_OCCUPIED:
					               icq_sendmsg( sok, Chars_2_DW( s_mesg->uin ), auto_rep_str_occ, NORM_MESS );
					               break;
				case STATUS_AWAY:
					               icq_sendmsg( sok, Chars_2_DW( s_mesg->uin ), auto_rep_str_away, NORM_MESS );
					               break;
				case STATUS_DND:
					               icq_sendmsg( sok, Chars_2_DW( s_mesg->uin ), auto_rep_str_dnd, NORM_MESS );
					               break;
				case STATUS_INVISIBLE:
					               icq_sendmsg( sok, Chars_2_DW( s_mesg->uin ), auto_rep_str_inv, NORM_MESS );
					               break;
				case STATUS_NA:
					               icq_sendmsg( sok, Chars_2_DW( s_mesg->uin ), auto_rep_str_na, NORM_MESS );
					               break;
				default:
					               M_print("You have encounterd a bug in my code :( I now own you a beer!\nGreetings Fryslan!\n");
         }
				M_print( "[ Sent auto-reply message ]\n" );
				log_event("Sending an auto-reply message to ","",last_recv_uin);
			}
      }
      Prompt();
      break;
   default: /* commands we dont handle yet */
       M_print( CLIENTCOL "\nThe response was %04X\t", cmd );
       M_print( "The version was %X\t", ver  );
       Time_Stamp();
       M_print( "\nThe SEQ was %04X\t", seq  );
       M_print( "The size was %d\n", len );
       if ( Verbose )
       {
            Hex_Dump( data, len );
       }
       M_print( NOCOL "\n" );
       Prompt();
       break;
   }

}

#if 0
   switch ( cmd )
   {
   case SRV_ACK:
      if ( Verbose )
      {
         M_print( "\nThe server acknowledged the %04x command.\n", 
            last_cmd[ seq ] );
         M_print( "The SEQ was %04X\n", seq );
      }
      break;
   case SRV_NEW_UIN:
      M_print( "\nThe new UIN is %ld!\n", Chars_2_DW( &data[2] ) );
      break;
   case SRV_UPDATE_FAIL:
      M_print( "\nFailed to update info.\n" );
      Prompt();
      break;
   case SRV_UPDATE_SUCCESS:
      M_print( "\nUser info successfully updated.\n" );
      Prompt();
      break;      
   case SRV_LOGIN_REPLY:
/*      UIN = Chars_2_DW( &pak.data[0] ); */
      our_ip = Chars_2_DW( &data[0] );
      M_print( "\nLogin successful! UIN : %lu\n", uin );
#if ICQ_VER == 0x0002
      M_print( " IP : %u.%u.%u.%u\t", data[4], data[5], data[6], data[7] );
#else
      M_print( " IP : %u.%u.%u.%u\t", data[0], data[1], data[2], data[3] );
#endif
      Time_Stamp();
      M_print( "\n" );
      snd_login_1( sok );
      snd_invis_list( sok );
      snd_contact_list( sok );
/*      icq_change_status( sok, set_status );*/
      Prompt();
      break;
   case SRV_RECV_MESSAGE:
         Recv_Message( sok, data );
      Prompt();
      break;
   case SRV_X1: /* unknown message  sent after login*/
      if ( Verbose )
         M_print( "\nAcknowleged SRV_X1 0x021C Begin messages?\n" );
      break;
   case SRV_X2: /* unknown message  sent after login*/
      if ( Verbose )
         M_print( "\nAcknowleged SRV_X2 0x00E6 Done old messages?\n" );
      Show_Quick_Status();
      Done_Login = TRUE;
      snd_got_messages( sok );
      Prompt();
      break;
   case SRV_INFO_REPLY:
      Display_Info_Reply( sok, data );
      Prompt();
      break;
   case SRV_EXT_INFO_REPLY:
      Display_Ext_Info_Reply( sok, data );
      Prompt();
      break;
   case SRV_USER_OFFLINE:
      User_Offline( sok, data );
      Prompt();
      break;
   case SRV_BAD_PASS:
      M_print( MESSCOL "\nYou entered an incorrect password." NOCOL "\n" );
      exit( 1 );
      break;
   case SRV_TRY_AGAIN:
      M_print( MESSCOL "\nServer is busy please try again.\nTrying again...\n");
      Prompt();
#ifdef UNIX
      if ( fork() == 0 )
      {
         sleep( 5 );
         Login( sok, UIN, &passwd[0], our_ip, our_port, set_status );
         exit( 0 );
      }
#else
      Login( sok, UIN, &passwd[0], our_ip, our_port, set_status );
#endif
      for ( i = 0; i< 1024; i++ )
      {
         serv_mess[ i ]=FALSE;
      }
     break;
   case SRV_USER_ONLINE:
      User_Online( sok, data );
      Prompt();
      break;
   case SRV_STATUS_UPDATE:
      Status_Update( sok, data );
      Prompt();
      break;
   case SRV_GO_AWAY:
      #ifdef FUNNY_MSGS 
      M_print( "\nServer sent \"Go away!!\" command.\t" );
      #else
      M_print( "\nServer has forced us to disconnect.  This may be because of network lag.\t" );
      #endif
      Time_Stamp();
      Quit = TRUE;
      Prompt();
      break;
   case SRV_END_OF_SEARCH:
      M_print( "\nSearch done.\n" );
      Prompt();
      break;
   case SRV_USER_FOUND:
      Display_Search_Reply( sok, data );
      Prompt();
      break;
   case SRV_SYS_DELIVERED_MESS:
      M_print( "\n" );
      s_mesg = ( SIMPLE_MESSAGE_PTR ) data;
      last_recv_uin = Chars_2_DW( s_mesg->uin );
      Print_UIN_Name( Chars_2_DW( s_mesg->uin  ) );
      M_print( " - Instant Message\a " );
      if ( Verbose )
         M_print( " Type = %04x\t", Chars_2_Word( s_mesg->type ) );
      Time_Stamp();
      Do_Msg( sok, Chars_2_Word( s_mesg->type ), Chars_2_Word( s_mesg->len ), 
           s_mesg->len + 2,last_recv_uin); 
      if ( 0xfe != *( ((unsigned char *) s_mesg ) + sizeof( s_mesg ) ) )
      {
         if ( auto_resp &&
				(Current_Status != STATUS_ONLINE) &&
				(Current_Status != STATUS_FREE_CHAT)  )
         {
				switch ( Current_Status )
				{
				case STATUS_OCCUPIED:
					               icq_sendmsg( sok, Chars_2_DW( s_mesg->uin ), auto_rep_str_occ, NORM_MESS );
					               break;
				case STATUS_AWAY:
					               icq_sendmsg( sok, Chars_2_DW( s_mesg->uin ), auto_rep_str_away, NORM_MESS );
					               break;
				case STATUS_DND:
					               icq_sendmsg( sok, Chars_2_DW( s_mesg->uin ), auto_rep_str_dnd, NORM_MESS );
					               break;
				case STATUS_INVISIBLE:
					               icq_sendmsg( sok, Chars_2_DW( s_mesg->uin ), auto_rep_str_inv, NORM_MESS );
					               break;
				case STATUS_NA:
					               icq_sendmsg( sok, Chars_2_DW( s_mesg->uin ), auto_rep_str_na, NORM_MESS );
					               break;
				default:
					               M_print("You have encounterd a bug in my code :( I now own you a beer!\nGreetings Fryslan!\n");
         }
				M_print( "[ Sent auto-reply message ]\n" );
				log_event("Sending an auto-reply message to ","",last_recv_uin);
			}
      }
      Prompt();
      break;
   default: /* commands we dont handle yet */
       M_print( CLIENTCOL "\nThe response was %04X\t", cmd );
       M_print( "The version was %X\t", ver );
       Time_Stamp();
       M_print( "\nThe SEQ was %04X\t", seq );
       M_print( "The size was %d\n", len );
       if ( Verbose )
       {
            Hex_Dump( pak.data, len );
       }
       M_print( NOCOL "\n" );
       Prompt();
       break;
   }
#endif
