/*
 * Copyright (c) 1999 Erick Engelke
 */
#include <rtos.h>
#include <net.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <strlst.h>
#include <httpd.h>

static void http_write( tcp_Socket *s, char *p )
{
    sock_write( s, p, strlen( p ));
}

void html_hdr( tcp_Socket *s, char *title )
{
    sock_puts( s, "\r\n\r\n<html><head><title>");
    sock_puts( s, title );
    sock_puts( s, "</title></head><body>");
}
void html_tail( tcp_Socket *s )
{
    sock_puts( s, "</body></html>");
}

void html_datestring( tcp_Socket *s, char *format, DWORD plusseconds )
{
    int len;
    char buf1[64], *buf2;
    struct tm *time_now;
    time_t secsnow;

    len = strlen( format ) + 64;
    if ( ( buf2 = kcalloc( len , 1 )) == NULL )
        sock_puts( s, "no memory");
    else {
        dos_enter();            // -ew 020401
        time( &secsnow );
        secsnow += plusseconds;
        time_now = localtime( &secsnow );

        strftime( buf1, sizeof( buf1 ),
            "%a, %d %b %Y %X %Z", time_now );
        sprintf( buf2, format, buf1 );
        dos_exit();             // -ew 020401
        sock_puts( s, buf2 );
        kfree( buf2 );
    }
}



#define HTTP_BUFSIZE 256
static void http_fname( char *base, char *fname, char *ext, char *buffer )
{
    char *p;

    while ( (p = strchr( fname, '/' )) != NULL ) *p = '\\';

    /* skip any preceding slashes, .., or D: entries */
    while ( fname[0] == '\\' ) fname++;
    while ( (strlen( fname ) > 2 ) && (fname[1] == ':')) fname += 2;
    while ( (strlen( fname ) > 2 ) && (fname[1] == '.')) fname += 2;

    *buffer = 0;    /* reset string */
    if ( base ) {
        strcpy( buffer, base );
        strcat( buffer, "\\");
    }
    strcat( buffer, fname );
    if ( ext != NULL ) {
        strcat( buffer, ".");
        strcat( buffer, ext );
    }
}
int http_dump( tcp_Socket  *s, char *base, char *fname, char *ext )
{
    FILE *f;
    char *buffer;
    char *p;
    int i;
    int retval = 0;

    buffer = kcalloc( HTTP_BUFSIZE, 1 );
    if ( buffer == NULL ) return -1;

    http_fname( base, fname, ext, buffer );

    dos_enter();
    f = fopen( buffer, "rb");
    dos_exit();
    if ( f == NULL ) {
        html_hdr( s, "File not found");
        sock_puts(s,"File: ");
        sock_puts(s, buffer );
        sock_puts(s, "not found");
        html_tail( s );
        retval = -1;
    } else {
        dos_enter();
        while ( (i = fread( buffer, 1, HTTP_BUFSIZE, f )) != 0 ) {
            dos_exit();
            sock_write( s, buffer, i );
            dos_enter();
        }
        fclose( f );
        dos_exit();
        retval = 0;
    }
    kfree( buffer );
    return( retval );
}
int http_shtml( tcp_Socket  *s, char *base, char *fname, char *ext,
    ssi_type *ssi_list, stringlist *cookies )
{
    FILE *f;
    char *buffer;
    char *p, *q;
    int i;
    int retval = -1;
    ssi_type *ssi;
    char ch;

    buffer = kcalloc( HTTP_BUFSIZE, 1 );
    if ( buffer == NULL ) return -1;

    http_fname( base, fname, ext, buffer );

    dos_enter();
    f = fopen( buffer, "rb");
    dos_exit();
    if ( f == NULL ) {
        html_hdr( s, "File not found");
        sock_puts(s,"File: ");
        sock_puts(s, buffer );
        sock_puts(s, "not found");
        html_tail( s );
        retval = -1;
    } else {
        retval = 0;
        while ( 1 ) {
            dos_enter();
            p = fgets( buffer, HTTP_BUFSIZE, f );
            dos_exit();
            if ( p == NULL ) break;
            p = buffer;
            while ( p != NULL ) {
                q = p;
                if ( (p = strchr( p, '#')) == NULL ) {
                    if ( *q )
                        sock_puts( s, q );
                } else {
                    if ( p[1] != '#' ) {
                        /* not SSI, straight text up to this point */
                        ch = *(++p);
                        *p = 0;
                        http_write( s, q );
                        *p = ch;    /* restore this first char */
                    }
                    else {
                        *p = 0;
                        http_write( s, q );
                        p = q = p+2;

                        p = strchr( p, '#');
                        /* tail can be either ## or #, but must be something */
                        if ( p == NULL ) continue;
                        *p = 0;
                        if ( *(++p) == '#' ) p++;

                        for ( ssi = ssi_list ; ssi->ssi_name != NULL ; ssi++ ) {
                            if ( !strcmp( ssi->ssi_name, q )) {
                                ssi->ssi_fn( s, cookies  );
                                break;
                            }
                        }
                        if ( ssi->ssi_name == NULL ) {
                            http_write( s, "--SSI not found: ");
                            http_write( s, q );
                            sock_puts( s, "--");
                        }
                    }
                }
            }
        }
        dos_enter();
        fclose( f );
        dos_exit();
    }
    kfree( buffer );
    return( retval );
}





/*
 * string_arg - find n'th argument within a command string, zero based
 *            - returns NULL if fewer args than necessary
 */
char *string_arg( char *string, int arg, char *buffer )
{
    char *p, *eow;
    char ch;
    int i;

    rip( string );  /* remove EOL */
    p = string;
    for ( i = 0 ; i < arg ; ++i ) {
        /* find end of word */
        while ( !isspace( ch = *p )) {
            if ( ch == 0 ) return( NULL );
            p++;
        }
        while ( isspace( ch = *p )) {
            if ( ch == 0 ) return( NULL );
            p++;
        }
    }
    /* we are now at the word we want */
    eow = p;
    i = 0;
    while ( !isspace( ch = *eow++ )) {
        if ( ch == 0 ) break;
        i++;
    }
    /* copy just the word, and then truncate string */
    memcpy( buffer, p, i );
    buffer[ i ] = 0;

    return( buffer );
}


#define HTTPPORT 80


/*
 * implement one http server
 */
void httpdthread( DWORD ptr )
{
    tcp_Socket *s;
    char cmd[6] = "";
    char *p, *q, *r, *t, *u, *ext;
    char *buffer;
    char cmdbuf[256];
    char file[ 256 ];
    int i;
    stringlist *cookies;

    void (*userproc)( tcp_Socket *s, char *cmd, char *name, char *ext,
        stringlist *sl );

    userproc = (void *)ptr;
#define HTTP_BUF_SIZE 1024
    buffer = kcalloc( HTTP_BUF_SIZE , 1);
    if ( buffer == NULL ) rt_halt("out of memory starting httpd");

    if ( userproc == NULL )
        rt_halt( "httpd passed user proc of NULL");

    s = kcalloc( sizeof( tcp_Socket ), 1 );


    do {
        cookies = NULL;
        memset( cmd, 0, sizeof( cmd ));
        ext = NULL;
        *file = 0;
        *cmd = 0;

        /* start listenning */
        tcp_listen( s, HTTPPORT, 0, 0, NULL, 0 );

        /* wait for a connection */
        do {
            rt_sleep( 0 );    /* just waiting */
            if ( tcp_tick( s ) == NULL ) goto reopen;
        } while ( ! sock_established( s ));

        *file = 0;
        sock_mode( s, TCP_MODE_ASCII );

        /* get each line of input text */
        do {
            while ( ! sock_dataready( s )) {
                rt_sleep(0);
                if ( tcp_tick( s ) == NULL ) goto reopen;
            }
            sock_gets( s, buffer, HTTP_BUF_SIZE );
            rip( buffer );   /* remove CR/LF */

            /* empty line signals end of request */
            if ( buffer[0] == 0 ) break;

if ( kdebug > 1 )
    cprintf("RECEIVED: %s\r\n", buffer );

            if ( !strncmp( buffer, "GET ", 4 ) ||
                 !strncmp( buffer, "POST", 4 ) ){
                memcpy( cmd, buffer, sizeof(cmd)-1);
                memcpy( cmdbuf, buffer, strlen( buffer ));
                cmd[ sizeof( cmd ) -1 ] = 0;
                for ( p = cmd ; *p ; ++p )
                    if ( isspace( *p ) ) *p = 0;

                p = string_arg( buffer, 1, file );
                if ( p != NULL ) {
                    /* find the extension */
                    ext = strrchr( file, '/' );
                    if ( ext == NULL ) ext = file;
                    ext = strrchr( file, '.' );
                    if ( ext ) *ext++ = 0;

                }
            } else if ( !strnicmp( buffer, "COOKIE:", 7 )) {
#define COOKIES
#ifdef COOKIES
                if ( cookies == NULL )
                    cookies = strlst_new();

                p = buffer + 7;
                while ( isspace( *p ) ) p++;
                /* p at start of each cookie */
                do {
                    r = NULL;
                    /* find BLAH=... */
                    if ( ( q = strchr( p, '=')) != NULL ) {
                        *q++ = 0;
                        /* see if any more in list */
                        if ( ( r = strchr( q, ' ')) != NULL )
                            *r++ =  0;

                        /* remove separting ';' */
                        if ( u = strchr( q, ';' )) *u = 0;

                        /* need a copy */
                        t = kstrdup( q );
                        strlst_adddata( cookies, p, t );
                    }
                } while ( ( p = r ) != NULL  );
#endif
            }

        } while ( 1 );

        sock_puts( s, "HTTP/1.1 200 OK\r\n"
                      "Server: eRTOS\r\n"
                      "Connection: close");

        html_datestring(s, "Date: %s", 0);
        html_datestring(s, "Last-Modified: %s", 0);

        /* prepare output */
        (*userproc)( s, cmd, file, ext, cookies );
reopen:
#ifdef FLUSHALL
        /* flush all input */
        sock_mode( s, TCP_MODE_BINARY );
        while ( ( i = sock_dataready( s )) > 0 ) {
            if ( i > sizeof( buffer )) i = sizeof( buffer );
            sock_read( s, buffer, i );
        }
#endif
        sock_close( s );

        /*
         * and wait for it to close
         */
        while ( tcp_tick( s ) )
            rt_sleep( 1 );

        /* free any cookies */
        if ( cookies != NULL ) {
            p = strlst_getfirst( cookies, &q, &r );
            while ( p != NULL ) {
                if ( r != NULL ) kfree( r );
                p = strlst_getnext( cookies, &q, &r );
            }
            strlst_freeall( cookies );
        }

        /* now we are unthreaded, start whole process again */
    } while ( 1 );
}

