/*

  DBOX Module
  Copyright (C) 1994-2000 Daniel Kroening <kroening@handshake.de>

  Purpose: 

*/

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#include <general.h>
#include <base64.h>
#include <stringtools.h>
#include "http.h"

#include <logf.h>

void httpt::parse_command()
 {
  char *t1, *t2, old;

  method=UNKNOWN;

  if(command=="")
   {
    url=version="";
    return;
   }

  //
  // Methode
  //

  char *c=strdup(command.c_str());

  t2=c;
  while(*t2!=' ' && *t2!='\t' && *t2!=0) t2++;
  old=*t2;
  *t2=0;
  
  if(stringcasecmp(command, "GET")==0)
    method=GET;
  else if(stringcasecmp(command, "PUT")==0)
    method=PUT;
  else if(stringcasecmp(command, "POST")==0)
    method=POST;

  *t2=old;
  while(*t2==' ' || *t2=='\t') t2++;
  t1=t2;

  if(t1[0]==0) 
   {
    url=version="";
    free((void *)c);
    return;
   }

  // 
  // URL
  // 

  while(*t2!=' ' && *t2!='\t' && *t2!=0 && *t2!='?') t2++;
  old=*t2;
  *t2=0;
  url=t1;
  decode_url(url);
  *t2=old;

  if(old=='?')
   {
    t1=t2+1;
    while(*t2!=' ' && *t2!='\t' && *t2!=0) t2++;
    old=*t2;
    *t2=0;
    parse_parameter(t1);
    *t2=old;
   }

  while(*t2==' ' || *t2=='\t') t2++;
  t1=t2;

  if(t1[0]==0)
   {
    version="";
    free(c);
    return;
   }

  // 
  // Version
  //

  version=t1;

  free(c);
 }

void httpt::parse_parameter(char *str)
 {
  char *t;
  parametert p;

  if(str==NULL) return;

  t=str;
  while(*t!=0)
   {
    if(*t==-1)
      *t=' ';

    t++;
   }

  while(str[0]!=0)
   {
    t=strchr(str, '=');
    if(t==NULL) return;
    *t=0;
    p.n=parameter;
    string _name=str;
    decode_url(_name);
    p.name=strdup(_name.c_str());
    *t='=';
    str=t+1;

    string _inhalt;
    t=strchr(str, '&');
    if(t==NULL)
     {
      _inhalt=str;
      str="";
     }
    else
     {
      *t=0;
      _inhalt=str;
      *t='&';
      str=t+1;
     }

    decode_url(_inhalt);
    p.inhalt=strdup(_inhalt.c_str());

    parameter=new parametert;
    *parameter=p;

   }
 }

const char *httpt::getparameter(const char *name)
 {
  return get_parameterfromlist(name, parameter);
 }

const char *httpt::get_parameter(const string &name)
 {
  return get_parameterfromlist(name.c_str(), parameter);
 }

const char *httpt::get_header(const char *name)
 {
  return get_parameterfromlist(name, header);
 }

const char *httpt::get_parameterfromlist(const char *name, parametert *list)
 {
  parametert *p;

  p=list;
  while(p!=NULL)
   {
    if(stricmp(name, p->name)==0)
      return p->inhalt;

    p=p->n;
   }

  return NULL;
 }

httpt::httpt()
 {
  parameter=header=NULL;
  method=UNKNOWN;
 }

void httpt::clear()
 {
  command=url=version="";

  if(parameter!=NULL)
   {
    parametert *p;
    while(parameter!=NULL)
     {
      p=parameter->n;
      free(parameter->name);
      free(parameter->inhalt);
      delete parameter;
      parameter=p;
     }
   }
 }

void httpt::basic_auth(char *username, char *password, int maxlen)
 {
  const char *header;
  char buffer[1000], *tptr;
  int len;

  username[0]=password[0]=0;

  header=get_header("Authorization");

  if(header==NULL) return;

  if(strncmp(header, "Basic ", 6)!=0) return;

  header+=6;

  len=base64_decode(header, buffer, 999);
  buffer[len]=0;

  tptr=strchr(buffer, ':'); 
  if(tptr==NULL) return;

  *(tptr++)=0;
  strmaxcpy(username, buffer, maxlen-1);
  strmaxcpy(password, tptr, maxlen-1);
 }

httpt::~httpt()
 {
  clear();
 }

void httpt::decode_url(string &url)
 {
  char mime_data=0;
  int status=0;
  const string buffer=url;
  url="";

  for(unsigned i=0; i<buffer.size(); i++)
   {
    char data=buffer[i];

    switch(data)
     {
     case '\n':
     case '\r':
     case 0:
      return;

     case '%':
      status=1;
      break;
    
     case '+':
      url+=' ';
      break;

     default:
      switch(status)
       {
       case 0:
        url+=data;
        break;

       case 1:
        status++;
        if(isascii(data) && isxdigit(data))
         {
          if(isdigit(data))
            mime_data=(data-'0')<<4;
          else
            mime_data=(tolower(data)-'a'+10)<<4;
         }
        else if(data=='%')
          url+=data;
        break;

       case 2:
        status=0;
        if(isascii(data) && isxdigit(data))
         {
          if(isdigit(data))
            mime_data|=data-'0';
          else
            mime_data|=tolower(data)-'a'+10;
          
          url+=mime_data;
         }
        break;

       default:
        abort();
       }
     }
   }
 }

void cgi_httpt::cgi_parse()
 {

 }

void handle_httpt::read_header()
 {
  string buffer;
  parametert p;

  while(TRUE)
   {
    read_line(buffer);
    if(buffer=="") return;

    char *tptr=strchr(buffer.data(), ':');
    if(tptr==NULL) return;
    *tptr=0;
    tptr++;
    while(*tptr==' ' || *tptr=='\t') tptr++;

    if(buffer[0]!=0)
     {
      p.n=header;
      p.name=strdup(buffer.c_str());
      p.inhalt=strdup(tptr);

      header=new parametert;
      *header=p;
     }
   }
 }

void handle_httpt::read_request(int _handle)
 {
  handle=_handle;

  read_command();
  parse_command();

  if(version!="")
    read_header();
 }

void handle_httpt::read_line(string &buffer)
 {
  buffer="";

  while(TRUE)
   {
    char data;

    if(read(handle, &data, 1)!=1)
      return;
 
    switch(data)
     {
     case '\n':
     case 0:
      return;

     case '\r':
      break;

     default:
      buffer+=data;
     }
   }
 }

void handle_httpt::read_command()
 {
  read_line(command);
 }

void get_url_httpt::parse_get_url(const string &_url)
 {
  command="GET "+_url;
  parse_command();
 }

void mkrfc1123(time_t t, char *s)
 {
  struct tm *gmt;

  gmt=gmtime(&t);
  s[0]=0;
  strftime(s, 99, "%a, %d %b %Y %H:%M:%S GMT", gmt);
 }


syntax highlighted by Code2HTML, v. 0.9.1