/**************************
 *   Projekt SS2006, wiki *
 **************************/


#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

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

/* CGI Environment Variablen */
#define SERVER_NAME getenv("SERVER_NAME")
#define SERVER_PROTOCOL getenv("SERVER_PROTOCOL")
#define SERVER_PORT getenv("SERVER_PORT")
#define PATH_INFO getenv("PATH_INFO")
#define PATH_TRANSLATED getenv("PATH_TRANSLATED")
#define SCRIPT_NAME getenv("SCRIPT_NAME")
#define REMOTE_HOST getenv("REMOTE_HOST")
#define REMOTE_ADDR getenv("REMOTE_ADDR")
#define CONTENT_TYPE getenv("CONTENT_TYPE")
#define REQUEST_METHOD getenv("REQUEST_METHOD")
#define CONTENT_LENGTH getenv("CONTENT_LENGTH")
#define QUERY_STRING getenv("QUERY_STRING")

#define FILEPATH "/home/wiki/"

/* Fuer's Testen definieren wir die Dinger selbst */
// #define REQUEST_METHOD "GET"
// #define CONTENT_LENGTH "119"
// #define QUERY_STRING "Begriff=G%E4nsegeier&Autor=J%FCrgen+Plate&Datum=05.04.06&Artikel=G%E4nsegeier+geh%F6ren+zur+Familie+der+Habichtartigen."

/* Funktionsprototypen */
char x2c(char hex[]);
void unescape(char *url);
void CGIReadInput(void);

void CGIPrintEnv(void);
char *escape_input(char *str);

/* Hier geht's los */
int main(int argc, char *argv[])
  {
  printf("Content-Type: text/html\r\n\r\n");
  printf("<HTML><HEAD><TITLE>Wiki-Eingabe</TITLE></HEAD>\n");
  printf("<BODY><H1>Wiki-Eingabe</H1>\n");

  CGIReadInput();
  printf("<P><B>Ihre Daten wurden gespeichert!</B>\n");
  printf("</BODY></HTML>\n");
  return EXIT_SUCCESS;
  }

char x2c(char hex[])
  {
  /* Hexadezimal zu Character Umwandlung */
  char digit;

  if (hex[0] >= 'A') digit = ((hex[0] & 0xdf) - 'A') + 10;
  else               digit = (hex[0] - '0');
  digit = digit * 16;
  if (hex[1] >= 'A') digit = digit + ((hex[1] & 0xdf) - 'A') + 10;
  else               digit = digit + (hex[1] - '0');
  return(digit);
  /* Das ginge sogar noch einfacher:
     digit = (hex[0] >= 'A' ? ((hex[0] & 0xdf) - 'A')+10 : (hex[0] - '0'));
     digit = digit * 16;
     digit += (hex[1] >= 'A' ? ((hex[1] & 0xdf) - 'A')+10 : (hex[1] - '0')); */
  }

void unescape(char *url)
  /* Diese Funktion wandelt eine URL wieder in eine Folge
     von ASCII-Zeichen um */
  {
  int x, y;
  char hex[2];

  for (x=0,y=0; url[y] != '\0'; x++,y++)
    {
    if (url[y] == '+')           /* Leerzeichen restaurieren */
      url[x] = ' ';
    else if(url[y] == '%')       /* Hexadezimalangabe */
      {
      hex[0] = url[y+1];
      hex[1] = url[y+2];
      y = y + 2;
      url[x] = x2c(hex);
      }
    else
      url[x] = url[y];           /* 'normales' Zeichen */
    }
  url[x] = '\0';                 /* Stringende-Zeichen anhängen */
  }

/* CGIReadInput ist noch nicht fertig: Abspeichern in Datei fehlt noch
   Die Daten kommen in der Reihenfolge Begriff, Autor, Datum, Artikel.
   Die zu öffnende Datei erhält den Begriff als Namen, in die erste
   Zeile werden Begriff, Autor und Datum geschrieben, jeweils durch
   Doppelpunkt getrennt. In die Folgenden Zeilen wird der Artikel
   geschrieben (mit fwrite). */

void CGIReadInput(void)
  /* Bearbeiten der CGI-Daten und Aufspalten in
     die Paare Name/Wert. Es werden GET- und
     POST-Requests verarbeitet. */
  {
  int i, j, content_length, maxlen;
  short NM = 1; /* Statusvariable, NM=1: Name, NM=0: Wert */
  char *input, *name, *value, *filename;
  FILE *fp;

  /* Eingabe prüfen */
  if (REQUEST_METHOD == NULL)
    {
    fprintf(stderr,"Error: REQUEST_METHOD is null\n");
    exit(1);
    }
  if (CONTENT_LENGTH == NULL)
    {
    fprintf(stderr,"Error: CONTENT_LENGTH is null\n");
    exit(1);
    }

  /* Benoetigte Werte holen und Speicher reservieren */
  content_length = atoi(CONTENT_LENGTH);
  maxlen = content_length - 1;
  /* genügend Speicher fuer die Eingabe reservieren */
  input = malloc(sizeof(char) * content_length + 1);
  /* Name und Wert koennen maximal so lang sein wie die Eingabe */
  name = malloc(sizeof(char) * content_length + 1);
  value = malloc(sizeof(char) * content_length + 1);
  filename = malloc(sizeof(char) * content_length + 1);
  if (!strcmp(REQUEST_METHOD,"POST"))
    { /* Daten von der Standardeingabe lesen */
    if (fread(input,sizeof(char),content_length,stdin) != content_length)
      {
      /* consistency error. */
      fprintf(stderr,"Error: input length < CONTENT_LENGTH\n");
      exit(1);
      }
    }
  else if (!strcmp(REQUEST_METHOD,"GET"))
    { /* Daten aus der Umgebungsvariablen QUERY_STRING holen */
    if (QUERY_STRING == NULL)
      {
      fprintf(stderr,"Error: QUERY_STRING is null\n");
      exit(1);
      }
    strcpy(input,QUERY_STRING);
    }
  else
    { /* error: invalid request method */
    fprintf(stderr,"Error: REQUEST_METHOD invalid\n");
    exit(1);
    }

  /* Daten aufsplitten */
  j = 0;
  for (i = 0; i < content_length; i++)
    {
    if (input[i] == '=')
      { /* Name zuende, nun Wert verarbeiten */
      name[j] = '\0';
      unescape(name);
      if (i == maxlen)
        { /* Ende der Eingabe, kein Wert */
        strcpy(value,"");
        /* abspeichern */
        printf ("%s --> '%s'<br>\n",name, value);

        }
      j = 0; NM = 0;
      }
    else if ((input[i] == '&') || (i == maxlen))
      { /* Wertangabe zuende */
      if (i == maxlen)
        { /* Ende der Eingabe, letzter Wert */
        value[j] = input[i];
        j++;
        }
      value[j] = '\0';
      unescape(value);
      /* abspeichern */
      printf ("%s --> '%s'<br>\n",name, value);
      if (!strcmp(name,"Begriff"))
        {
        strcat(filename,FILEPATH);
        strcat(filename,value);
        printf ("Dateiname --> '%s'<br>\n", filename);
        if ((fp=fopen(filename,"wt"))==NULL)
          {
          fprintf(stderr,"Schreiben in Datei %s nicht möglich!\n",filename);
          exit(1);
          }
        }
      fprintf(fp,"%s",value);
      if ( (!strcmp(name,"Begriff")) || (!(strcmp(name,"Autor"))) )
        {
        fprintf(fp,":");
        }
      else
        {
        fprintf(fp,"\n");
        }

      if (!strcmp(name,"Artikel"))
        {
        fclose(fp);
        }

      j = 0; NM = 1;
      }
    else if (NM)
      { /* Name wird gerade gelesen */
      name[j] = input[i];
      j++;
      }
    else if (!NM)
      { /* Wert wird gerade gelesen */
      value[j] = input[i];
      j++;
      }
    }
  }
