#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

/* Port fuer die Requests */
#define PORT 7777

/* Puffergroesse */
#define BUFSIZE 4096

#define SMAX 100          /* maximale Schluessellaenge */
#define ALPHA 96          /* Alphabetlaenge */

int keylen;               /* Laenge des Schluesselwortes */
char key[SMAX];           /* Schluesselwort in Form von Offsets */

char secret[] = "Mirakulix"; /* Codeschluessel */

char test[] = "Hello\n";
char buffer[BUFSIZE];

void decode(char *key, char *buffer);
void encode(char *key, char *buffer);
void mkkey(char *secret, char *key, int *keylen);

int main(int argc, char **argv)
  {
  struct sockaddr_in host_addr;
  int size;
  int sock;
  struct hostent *host;

  if (3 != argc) 
    {
    fprintf(stderr, "Usage: %s <servername> <Kommando>\n", argv[0]);
    return -1;
    }

  host = gethostbyname(argv[1]);
  if (host == NULL)
    {
    fprintf(stderr, "Unbekannter Host %s\n",argv[1]);
    return -1;
    }

  /* 2. Parameter (Kommand) in den Buffer kopieren */ 
  strncpy(buffer,argv[2],BUFSIZE-1);

  mkkey(secret, key, &keylen);

  /* Socket erzeugen */
  sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock < 0)
    {
    fprintf(stderr, "Error: socket\n");
    return -1;
    }
  /* Socket an das Ziel binden */
  memset( &host_addr, 0, sizeof (host_addr));
  host_addr.sin_family = AF_INET;
  host_addr.sin_addr = *((struct in_addr *)host->h_addr);
  host_addr.sin_port = htons(PORT);
  /* Verbindung aufbauen */
  if (connect(sock, (struct sockaddr *)&host_addr, sizeof(host_addr)) == -1)
    {
    fprintf(stderr, "Error: connect\n");
    return -1;
    }
  /* Dialog mit dem Server */
  encode(key, buffer);
  write(sock, buffer, strlen(buffer));
  memset(buffer, 0, sizeof(buffer));
  size = read(sock, buffer, BUFSIZE-1);
  if (size == -1)
    {
    fprintf(stderr, "reading data failed\n");
    return -1;
    }

  printf("%d Bytes: %s\n",size,buffer);
  /* Socket wieder freigeben */
  close(sock);
  return 0;
  }

/*
 * Verschluesseln des Textes im buffer
 * Es werden nur Zeichen im Bereich von 0x32 bis 0x128
 * verschluesselt. Andere Zeichen werden einfach
 * unveraendert durchgereicht.
 * Der buffer enthaelt nach Ende der Funktion den
 * codierten Text --> der urspruenglieche Inhalt
 * wird ueberschrieben.
 */
void encode(char *key, char *buffer)
  {
  int c;
  int n = 0;
  int j = 0;
  while (buffer[j] != 0 )
    {
    if (' ' <= buffer[j] && buffer[j] <= 128)
      {
      c = (buffer[j] - ' ' + key[n]) % ALPHA;
      buffer[j] = c + ' ';
      n = (n + 1) % keylen;
      }
    j++;
    }
  }

/*
 * Entschluesseln des Textes im buffer
 * Es werden nur Zeichen im Bereich von 0x32 bis 0x128
 * entschluesselt. Andere Zeichen werden einfach
 * unveraendert durchgereicht.
 * Der buffer enthaelt nach Ende der Funktion den
 * decodierten Text --> der urspruenglieche Inhalt
 * wird ueberschrieben.
 */
void decode(char *key, char *buffer)
  {
  int c;
  int n = 0;
  int j = 0;
  while (buffer[j] != 0 )
    {
    if (' ' <= buffer[j] && buffer[j] <= 128)
      {
      c = (buffer[j] - ' ' - key[n]);
      if (c < 0) c = c + ALPHA;
      buffer[j] = c + ' ';
      n = (n + 1) % keylen;
      }
    j++;
    }
  }

/* key erzeugen:
 * In key werden die Offsets gespeichert: 'a' --> 0, 'b' --> 1 usw.
 * Es wird nicht zwischen Gross- und Kleinbuchstaben unterschieden.
 * nicht-alphabetische Zeichen werden ignoriert (--> 0).
 * Da das key-array Nullen enthaelt, muss dessen Laenge getrennt
 * in der Variable keylen gespeichert werden.
 */
void mkkey(char *secret, char *key, int *keylen)
  {
  int len = 0;
  while (secret[len] != '\0')
    {
    if (isupper(secret[len])) key[len] = secret[len] - 'A';
    else if (islower(secret[len])) key[len] = secret[len] - 'a';
    else key[len] = 0;
    len++;
    }
  *keylen = len;
  }


