/*********************************************
**********************************************
This file has the "ui" functions that read input
and send messages etc.

This software is provided AS IS to be used in
whatever way you see fit and is placed in the
public domain.

Author : Matthew Smith April 23, 1998
Contributors : Nicolas Sahlqvist April 27, 1998
               Michael Ivey May 4, 1998
               Ulf Hedlund -- Windows Support
               Michael Holzt May 5, 1998
Changes :
**********************************************
**********************************************/

#include "micq.h"
#include "datatype.h"
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
  #include <winsock2.h>
#else
  #include <unistd.h>
  #include <netinet/in.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <sys/time.h>
  #include <sys/socket.h>
  #include <arpa/inet.h>
  #include <netdb.h>
#endif
#include <fcntl.h>
#include <time.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>

static DWORD last_uin=0;
static DWORD multi_uin;
static void Show_Status( void );

#define UIN_DELIMS ":|/" /* add space if you don't want your nick names to have spaces */
#define END_MSG_STR "."
#define CANCEL_MSG_STR "#"
#define W_SEPERATOR MESSCOL "============================================" NOCOL "\n"

BOOL Do_Multiline( SOK_T sok, char *buf )
{
   static int offset=0;
   static char msg[1024];
   
   msg[ offset ] = 0;
   if ( ! strcmp( buf, END_MSG_STR ) )
   {
      icq_sendmsg( sok, multi_uin, msg );
      printf( "Message sent!\n" );
      last_uin = multi_uin;
      offset = 0;
      return FALSE;
   }
   else if ( ! strcmp( buf, CANCEL_MSG_STR ) )
   {
      printf( "Message canceled!\n" );
      last_uin = multi_uin;
      offset = 0;
      return FALSE;
   }
   else
   {
      if ( offset + strlen( buf ) < 1024 )
      {
         strcat( msg, buf );
         strcat( msg, "\r\n" );
         offset += strlen( buf ) + 2;
         return TRUE;
      }
      else
      {
         printf( "Message sent before last line buffer is full\n" );
         icq_sendmsg( sok, multi_uin, msg );
         last_uin = multi_uin;
         offset = 0;
         return FALSE;
      }
   }
}

BOOL Do_Multiline_All( SOK_T sok, char *buf )
{
   static int offset=0;
   static char msg[1024];
   int i;
   
   msg[ offset ] = 0;
   if ( ! strcmp( buf, END_MSG_STR ) )
   {
      for ( i=0; i < Num_Contacts; i++ )
         icq_sendmsg( sok, Contacts[i].uin, msg );
      printf( "Message sent!\n" );
      offset = 0;
      return FALSE;
   }
   else if ( ! strcmp( buf, CANCEL_MSG_STR ) )
   {
      printf( "Message canceled!\n" );
      offset = 0;
      return FALSE;
   }
   else
   {
      if ( offset + strlen( buf ) < 1024 )
      {
         strcat( msg, buf );
         strcat( msg, "\r\n" );
         offset += strlen( buf ) + 2;
         return TRUE;
      }
      else
      {
         printf( "Message sent before last line buffer is full\n" );
         for ( i=0; i < Num_Contacts; i++ )
            icq_sendmsg( sok, Contacts[i].uin, msg );
         offset = 0;
         return FALSE;
      }
   }
}

/******************************************************
Read a line of input and processes it.
*******************************************************/
void Get_Input( SOK_T sok )
{
   char buf[1024]; /* This is hopefully enough */
   char *cmd;
   char *arg1;
   static status = 0;
   DWORD uin;
   
   memset( buf, 0, 1024 );
   M_fdnreadln( STDIN, buf, 1024 ); /* assumes we're line buffered input */
   buf[1023]=0; /* be safe */
   if ( status == 1 )
   {
      if ( ! Do_Multiline( sok, buf ) )
      {
         status = 2;
      } else {
	   printf ( "msg> ");
	   fflush(stdout);
   	}
   }
   else if ( status == 3 )
   {
      if ( ! Do_Multiline_All( sok, buf ) )
      {
         status = 2;
      } else {
	   printf ( "msg all> ");
	   fflush(stdout);
   	}
   }
   else
   {
      if ( buf[0] != 0 )
      {
         cmd = strtok( buf, " \n\t" );
         if ( cmd == NULL )
            goto done;  /* ARRRGGGGHHHH!!!! I hate gotos */
         if ( ( ! strcasecmp( cmd , "quit" ) ) ||
              ( ! strcasecmp( cmd , "/quit" ) ) )
         {
            Quit = TRUE;
         }
         else if ( ! strcasecmp( cmd, quit_cmd ) )
         {
            Quit = TRUE;
         }
         else if ( ! strcasecmp( cmd, change_cmd ) )
         {
            arg1 = strtok( NULL, " \n\r" );
            if ( arg1 == NULL )
            {
               printf(  CLIENTCOL "Status modes: \n" );
               printf( "Status online         %d\n", STATUS_ONLINE );
               printf( "Status Away           %d\n", STATUS_AWAY );
               printf( "Status Do not Disturb %d\n", STATUS_DND );
               printf( "Status Not Available  %d\n", STATUS_NA );
               printf( "Status Free for Chat  %d\n", STATUS_FREE_CHAT );
               printf( "Status Occupied       %d\n", STATUS_OCCUPIED );
               printf( "Status Not Available  %d\n", STATUS_NA );
               printf( "Status Invisible      %d\n", STATUS_INVISIBLE );
               printf( NOCOL "\n" );
            }
            else
            {
               icq_change_status( sok, atoi( arg1 ) );
               Print_Status( Current_Status );
               printf( "\n" );
            }
         }
	      else if ( ! strcasecmp( cmd, online_cmd ) ) /* online command */
	      {
	          icq_change_status( sok, STATUS_ONLINE );
             Print_Status( Current_Status );
             printf( "\n" );
	      }
	      else if ( ! strcasecmp( cmd, away_cmd ) ) /* away command */
	      {
	          icq_change_status( sok, STATUS_AWAY );
             Print_Status( Current_Status );
             printf( "\n" );
	      }
	      else if ( ! strcasecmp( cmd, na_cmd ) ) /* Not Available command */
	      {
	          icq_change_status( sok, STATUS_NA );
             Print_Status( Current_Status );
             printf( "\n" );
	      }
	      else if ( ! strcasecmp( cmd, occ_cmd ) ) /* Occupied command */
	      {
	          icq_change_status( sok, STATUS_OCCUPIED );
             Print_Status( Current_Status );
             printf( "\n" );
	      }
	      else if ( ! strcasecmp( cmd, dnd_cmd ) ) /* Do not Disturb  command */
	      {
	          icq_change_status( sok, STATUS_DND );
             Print_Status( Current_Status );
             printf( "\n" );
	      }
	      else if ( ! strcasecmp( cmd, ffc_cmd ) ) /* Free For Chat command */
	      {
	          icq_change_status( sok, STATUS_FREE_CHAT );
             Print_Status( Current_Status );
             printf( "\n" );
	      }
	      else if ( ! strcasecmp( cmd, inv_cmd ) ) /* Invisible command */
	      {
	          icq_change_status( sok, STATUS_INVISIBLE );
             Print_Status( Current_Status );
             printf( "\n" );
	      }
	      else if ( ! strcasecmp( cmd, search_cmd ) )
	      {
             arg1 = strtok( NULL, "\n" );
             if ( arg1 == NULL )
             {
               printf("Must enter email address.\n");
             }
             else
             {
   	          start_search( sok, arg1, "", "", "" );
             }
	      }
         else if ( ! strcasecmp( cmd, status_cmd ) ) 
         {
            Show_Status();
         }
         else if ( ! strcasecmp( cmd, list_cmd ) ) 
         {
            Show_Quick_Status();
         }
         else if ( ! strcasecmp( cmd, "msga" ) )
         {
            status = 3;
            printf( "msg all> " );
            fflush(stdout);
         }
         else if ( ! strcasecmp( cmd, reply_cmd ) ) /* reply command */
         {
            if ( last_recv_uin == 0 )
            {
               printf( "Must receive a message first\n" );
               goto done;
            }
            arg1 = strtok( NULL, "" );
            last_uin = last_recv_uin;
            if ( arg1 != NULL )
            {
               icq_sendmsg( sok, last_recv_uin, arg1 );
               printf( "Message sent to %ld\n", last_recv_uin );
            }
            else
            {
               status = 1;
               printf( "msg> " );
               fflush(stdout);
            }
         }
         else if ( ! strcasecmp( cmd, again_cmd ) ) /* again command */
         {
            if ( last_uin == 0 )
            {
               printf( "Must write one message first\n" );
               goto done;
            }
            arg1 = strtok( NULL, "" );
            if ( arg1 != NULL )
            {
               icq_sendmsg( sok, last_uin, arg1 );
               printf( "Message sent to %ld\n", last_uin );
            }
            else
            {
               status = 1;
               printf( "msg> " );
               fflush(stdout);
            }
         }
         else if ( ! strcasecmp( cmd, "clear"))
   	   {
      	 	clrscr();
      		goto done;
      	}
         else if ( ! strcasecmp( cmd, info_cmd ) )
         {
            arg1 = strtok( NULL, "" );
            if ( arg1 == NULL )
            {
               printf( "Need uin to send to\n" );
               goto done; /* sorry */
            }
            uin = nick2uin( arg1 );
            if ( -1 == uin )
            {
               printf( "%s not recognized as a nick name\n", arg1 );
               goto done;
            }
            printf( "%s's IP address is ", arg1 );
            Print_IP( uin );
            printf( "\tThe port is %d\n",(WORD) Get_Port( uin ) );
            printf( "\n" );
            send_info_req( sok, uin );
         }
         else if ( ! strcasecmp( cmd, add_cmd ) )
         {
            arg1 = strtok( NULL, " \t" );
            if ( arg1 != NULL )
            {
               uin = atoi( arg1 );
               arg1 = strtok( NULL, "" );
               if ( arg1 != NULL )
               {
                  Add_User( sok, uin, arg1 );
                  printf( "%s added.\n", arg1 );
               }
            }
            else
            {
               printf( SERVCOL "Must specify a nick name" NOCOL "\n" );
            }
         }
         else if ( ! strcasecmp( cmd, "rinfo" ) )
         {
            Print_UIN_Name( last_recv_uin );
            printf( "'s IP address is " );
            Print_IP( last_recv_uin );
            printf( "\tThe port is %d\n",(WORD) Get_Port( last_recv_uin ) );
            printf( "\n" );
            send_info_req( sok, last_recv_uin );
         }
         else if ( ( ! strcasecmp( cmd, "/help" ) ) ||/* again command */
                   ( ! strcasecmp( cmd, "help" ) ) )
         {
            printf( MESSCOL "%s" NOCOL"\t\tDisplays your autoreply status\n",auto_cmd );
            printf( MESSCOL "%s [on|off]" NOCOL "\tToggles sending messages when your status is DND, NA, etc.\n",auto_cmd );
            printf( MESSCOL "%s message" NOCOL "\tSets the message to send as an auto reply\n",auto_cmd );
            printf( MESSCOL "%s" NOCOL "\t\tDisplays the current status of everyone on your contact list\n",list_cmd);
            printf( MESSCOL "%s [#]" NOCOL "\tChanges your status to the status number.\n\t\tWithout a number it lists the available modes.\n",change_cmd);
            printf( MESSCOL "%s uin" NOCOL "\t Displays general info on uin\n", info_cmd );
            printf( MESSCOL "add uin nick" NOCOL "\tAdds the uin number to your contact list with nickname.\n" );
            printf( MESSCOL "clear" NOCOL "\t\tClears the screen.\n" );
            printf( MESSCOL "%s email@host" NOCOL "\tSearches for a ICQ user with the specified email address.\n", search_cmd );
	         printf( MESSCOL "%s" NOCOL "\t\tMark as Online.\n",online_cmd);
	         printf( MESSCOL "%s" NOCOL "\t\tMark as Away.\n",away_cmd);
            printf( MESSCOL "%s" NOCOL "\t\tMark as Not Available.\n",na_cmd);
            printf( MESSCOL "%s" NOCOL "\t\tMark as Occupied.\n",occ_cmd);
            printf( MESSCOL "%s" NOCOL "\t\tMark as Do not Disturb.\n",dnd_cmd);
            printf( MESSCOL "%s" NOCOL "\t\tMark as Free for Chat.\n",ffc_cmd);
            printf( MESSCOL "%s" NOCOL "\t\tMark as Invisible.\n",inv_cmd);
            printf( MESSCOL "%s\t" NOCOL "\tLogs off and quits\n",quit_cmd );
            printf( MESSCOL "msga\t\t" NOCOL "Sends a multiline message to everyone on your list.\n" );
            printf( MESSCOL "%s uin\t" NOCOL "Authorize uin to add you to their list\n", auth_cmd );
            printf( MESSCOL "%s uin/message" NOCOL "\tSends a message to uin\n", message_cmd );
            printf( MESSCOL "%s message" NOCOL "\tSends a message to the last person you sent a message to\n", again_cmd);
            printf( MESSCOL "%s message" NOCOL "\tReplys to the last person to send you a message\n", reply_cmd);
            printf( CLIENTCOL "\tSending a blank message will put the client into multiline mode.\n\tUse . on a line by itself to end message." NOCOL "\n" );
         }
         else if ( ! strcasecmp( cmd, auth_cmd ) )
         {
             arg1 = strtok( NULL, "" );
             if ( arg1 == NULL )
             {
                printf( "Need uin to send to\n" );
                goto done; /* sorry */
             }
             uin = nick2uin( arg1 );
             if ( -1 == uin )
             {
                printf( "%s not recognized as a nick name\n", arg1 );
                goto done;
             }
             icq_sendauthmsg( sok, uin );
         }
         else if ( ! strcasecmp( cmd, message_cmd ) ) /* "/msg" */
         {
            arg1 = strtok( NULL, UIN_DELIMS );
            if ( arg1 == NULL )
            {
               printf( "Need uin to send to\n" );
               goto done; /* sorry */
            }
            uin = nick2uin( arg1 );
            if ( -1 == uin )
            {
               printf( "%s not recognized as a nick name\n", arg1 );
               goto done;
            }
            arg1 = strtok( NULL, "" );
            last_uin = uin;
            if ( arg1 != NULL )
            {
               icq_sendmsg( sok, uin, arg1 );
               printf( "Message sent to %ld\n", uin );
            }
            else
            {
               status = 1;
               printf( "msg> " );
               fflush(stdout);
            }
         }
         else if ( ! strcasecmp( cmd, "auto" ) )
         {
            cmd = strtok( NULL, "" );
            if ( cmd == NULL )
            {
               printf( "Automatic replies are %s\n", auto_resp ? "On" : "Off" );
               printf( "The message is: \n%s\n", auto_rep_str );
               goto done;
            }
            if ( ! strcasecmp( cmd, "on" ) )
            {
               auto_resp = TRUE;
               printf( "Automatic replies are on.\n" );
            }
            else if ( ! strcasecmp( cmd, "off" ) )
            {
               auto_resp = FALSE;
               printf( "Automatic replies are off.\n" );
            }
            else
            {
               printf( "Automatic reply set\n" );
               strcpy( auto_rep_str, cmd );
            }
         }
         else 
         {
            printf( "Unknown command %s, type /help for help.\n", cmd );
         }
         done:  /* sorry I hate goto's also */
	     ;
      }
   }
   multi_uin = last_uin;
   if ( ( status != 1 ) && ( status != 3) )
   {
      if ( ! Quit )
         Prompt();
   }
}

static void Show_Status( void )
{
   int i;
   
   printf( "Your status is " );
   Print_Status( Current_Status );
   printf( "\n" );
   /*  First loop sorts thru all offline users */
   for ( i=0; i< Num_Contacts; i++ )
   {
      if ( ( S_DWORD )Contacts[ i ].uin > 0 )
      {
         if ( Contacts[ i ].status == STATUS_OFFLINE )
         {
            printf( "%8ld = ", Contacts[ i ].uin );
            printf( CONTACTCOL "%-20s\t" NOCOL, Contacts[ i ].nick );
            Print_Status( Contacts[ i ].status );
            if ( -1L != Contacts[ i ].last_time )
            {
               if ( Contacts[ i ].status  == STATUS_OFFLINE )
                  printf( " Last online at %s", ctime( (time_t *) &Contacts[ i ].last_time ) );
               else
                  printf( " Online since %s", ctime( (time_t *) &Contacts[ i ].last_time )  );
            }
            else
            {
               printf( " Last on-line unknown.\n" );
               /* if time is unknow they can't be logged on cause we */
               /* set the time at login */
            }
         }
      }
   }
   /* The second loop displays all the online users */
   for ( i=0; i< Num_Contacts; i++ )
   {
      if ( ( S_DWORD )Contacts[ i ].uin > 0 )
      {
         if ( Contacts[ i ].status != STATUS_OFFLINE )
         {
            printf( "%8ld = ", Contacts[ i ].uin );
            printf( CONTACTCOL "%-20s\t" NOCOL, Contacts[ i ].nick );
            Print_Status( Contacts[ i ].status );
            if ( -1L != Contacts[ i ].last_time )
            {
               if ( Contacts[ i ].status  == STATUS_OFFLINE )
                  printf( " Last online at %s", ctime( (time_t *) &Contacts[ i ].last_time ) );
               else
                  printf( " Online since %s", ctime( (time_t *) &Contacts[ i ].last_time )  );
            }
            else
            {
               printf( " Last on-line unknown.\n" );
               /* if time is unknow they can't be logged on cause we */
               /* set the time at login */
            }
         }
      }
   }
}

void Show_Quick_Status( void )
{
   int i;
   
   printf( "\n\n" W_SEPERATOR );
   printf( "%lu: ", UIN );
   printf( "Your status is " );
   Print_Status( Current_Status );
   printf( "\n" );
   /*  First loop sorts thru all offline users */
   /*  This comes first so that if there are many contacts */
   /*  The online ones will be less likely to scroll off the screen */
   printf( W_SEPERATOR );
   printf( "Users offline: \n" );
   for ( i=0; i< Num_Contacts; i++ )
   {
      if ( ( S_DWORD )Contacts[ i ].uin > 0 )
      {
         if ( Contacts[ i ].status == STATUS_OFFLINE )
         {
            printf( CONTACTCOL "%-20s\t" MESSCOL "(" , Contacts[ i ].nick );
            Print_Status( Contacts[ i ].status );
            printf( ")" NOCOL "\n" );
         }
      }
   }
   /* The second loop displays all the online users */
   printf( W_SEPERATOR );
   printf( "Users online: \n" );
   for ( i=0; i< Num_Contacts; i++ )
   {
      if ( ( S_DWORD )Contacts[ i ].uin > 0 )
      {
         if ( Contacts[ i ].status != STATUS_OFFLINE )
         {
            printf( CONTACTCOL " %-20s\t" MESSCOL "(", Contacts[ i ].nick );
            Print_Status( Contacts[ i ].status );
            printf( ")" NOCOL "\n" );
         }
      }
   }
   printf( W_SEPERATOR );
}
