/* main.c

   client
*/

#ifdef __cplusplus
#error Be sure you are using a C compiler...
#endif

#if defined (WIN32)

#include <winsock2.h>

#elif defined (linux) || defined (_POSIX_VERSION) || defined (_POSIX2_C_VERSION)\
 || defined (_XOPEN_VERSION)

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>             /* close */

#define INVALID_SOCKET -1
#define SOCKET_ERROR -1

#define closesocket(s) close (s)
typedef int SOCKET;
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;

#else
#error not defined for this platform
#endif

#include <stdio.h>
#include <stdlib.h>

/* macros ============================================================== */

#define TELNET 23
#define IMAP 143

#define PORT TELNET
#define IP "127.0.0.1"

/* constants =========================================================== */
/* types =============================================================== */
/* structures ========================================================== */
/* private data ======================================================== */
/* private functions =================================================== */

/* ---------------------------------------------------------------------
   --------------------------------------------------------------------- */
static int app (void)
{
   int err = 0;

   /* open a socket in TCP/IP mode. */
   SOCKET sock = socket (AF_INET, SOCK_STREAM, 0);

   if (sock != INVALID_SOCKET)
   {
      printf ("socket %d is now opened in TCP/IP mode\n", sock);

      {
         int sock_err;
         /* connection data */
         SOCKADDR_IN sin = { 0 };

         /* server IP address */
         sin.sin_addr.s_addr = inet_addr (IP);

         /* protocol family (IP) */
         sin.sin_family = AF_INET;

         /* destination port */
         sin.sin_port = htons (PORT);

         /* client connection request (blocking) */
         printf ("waiting for a connection to the server on %s:%d...\n",
                 IP, PORT);
         sock_err = connect (sock, (SOCKADDR *) & sin, sizeof sin);

         if (sock_err != SOCKET_ERROR)
         {
            printf ("client connected with socket %d from %s:%d\n",
                    sock, inet_ntoa (sin.sin_addr), htons (sin.sin_port));
            {
               int end = 0;
               do
               {
                  char data[128];

                  /* prompt */
                  printf ("> ");

                  /* wait for a command (blocking) */
                  fgets (data, sizeof data, stdin);

                  /* send the command */
                  send (sock, data, strlen (data), 0);

                  /* wait for the response (blocking) */
                  sock_err = recv (sock, data, (sizeof data - 1), 0);

                  if (sock_err != SOCKET_ERROR)
                  {
                     size_t nb_rec = sock_err;
                     if (nb_rec > 0)
                     {
                        /* convert to string */
                        data[nb_rec] = 0;
                        /* display the answer */
                        printf ("%s\n", data);
                     }
                     else
                     {
                        puts ("client is disconnected");
                        end = 1;
                     }
                  }
                  else
                  {
                     perror ("socket.recv");
                     err = 1;
                     end = 1;
                  }
               }
               while (!end);
            }
            shutdown (sock, 2);
            printf ("closing client socket %d...\n", sock);
            closesocket (sock), sock = INVALID_SOCKET;
         }
         else
         {
            perror ("socket.connect");
            err = 1;
         }

         printf ("closing socket %d...\n", sock);

         /* close the socket. */
         sock_err = closesocket (sock), sock = INVALID_SOCKET;

         printf ("the socket is now closed\n");

         if (sock_err)
         {
            perror ("socket.close");
            err = 1;
         }
      }
   }
   else
   {
      perror ("socket.open");
      err = 1;
   }

   return err;
}

/* entry point ========================================================= */

/* ---------------------------------------------------------------------
   --------------------------------------------------------------------- */
int main (void)
{
   int ret;
#if defined (WIN32)
   WSADATA wsa_data;
   int err = WSAStartup (MAKEWORD (2, 2), &wsa_data);

   if (!err)
   {
      puts ("WIN: winsock2: OK");
#else
   int err;
#endif

   err = app ();

#if defined (WIN32)
   WSACleanup ();
}
#endif

if (err)
{
   ret = EXIT_FAILURE;
}
else
{
   ret = EXIT_SUCCESS;
}

system ("pause");

return ret;
}
