/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1990-2006 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
/*
 * File: ifs_httpcs.c
 */

#include "ifs_agent.h"
#include <stdio.h>

struct {
    int		version;
} HttpData;

/*
 *name: HttpConvert
 *	create a file of reference entries from the HTML document.
 */
int
HttpConvert( srcfile, htmlfile, linkfile )
char	*srcfile;
char	*htmlfile;
char	*linkfile;
{
    FILE	*fsrc, *fhtml, *flink;
    char	buf[ STRLEN ];
    char	*ptr, *p1, *p2;
    int		len;
    int		textflag = 0;

    if( (fsrc = fopen( srcfile, "r" )) == NULL ) {
	return -1;
    }
    if( (fhtml = fopen( htmlfile, "w" )) == NULL ) {
	fclose( fsrc );
	return -1;
    }
    if( (flink = fopen( linkfile, "w" )) == NULL ) {
	fclose( fhtml );
	fclose( fsrc );
	return -1;
    }

    /* parse header */
    while( fgets( buf, sizeof(buf), fsrc ) != NULL ) {
	fprintf( flink, "%s", buf );
	if( buf[0] == '\n' || buf[0] == '\r' )
	    break;
	if( strncmp( buf, "Content-Type: text", 18 ) == 0 )
	    textflag = 1;
    }

    if( textflag ) {
	/* parse htmlfile */
	while( fgets( buf, sizeof(buf), fsrc ) != NULL ) {
	    fprintf( fhtml, "%s", buf );
	    ptr = buf;
	    while( (p1 = strchr( ptr, '<' )) != NULL &&
		   (p2 = strchr( p1,  '>' )) != NULL ) {
		p1++;
		*p2++ = '\0';

		/* <a href="..."> */
		if( (*p1 == 'a' || *p1 == 'A') && p1[1] == ' ' )
		    fprintf( flink, "<%s>\n", p1 );
		ptr = p2;
	    }
	}
    } else {
	/* dump binary data */
	while( (len = fread( buf, 1, sizeof(buf), fsrc )) > 0 )
	    fwrite( buf, 1, len, fhtml );
    }

    fclose( flink );
    fclose( fhtml );
    fclose( fsrc );
    return 0;
}

/*
 *name: HttpXfer
 *	transfer a file from web server
 */
int
HttpXfer( srv, rpath, linkfile, tmpfile )
struct server_info *srv;
char	*rpath;
char	*linkfile;
char	*tmpfile;
{
    struct mount_item	*mitem = srv->mitem;
    NetFile	*nFile;
    FILE	*fp, *fout;
    char	buf[ STRLEN ], *ptr;
    char	line[ STRLEN ];
    int		port, len, ans = -1;
    
    if( (port = mitem->port) <= 0 )
	port = 80;
    if( (fout = fopen( tmpfile, "w" )) == NULL ) {
	logit( "<http>: tmpfile open error\n" );
	return -1;
    }
    if( (nFile = NetConnect( srv, mitem->host, port )) == NULL ) {
	fclose( fout );
	logit( "<http>: connect error\n" );
	return -1;
    }
    sprintf( buf, "GET %s HTTP/1.0\n", rpath );
    NetWrite( nFile, buf, strlen(buf) );
    logit( buf );

    /* If-Modified-Since: <Last-Modified> */
    /* -------- ignore this feature --------
    if( (fp = fopen( linkfile, "r" )) != NULL ) {
	while( fgets( line, sizeof(line), fp ) != NULL && line[0] != '\n' ) {
	    if( strncasecmp( line, "Last-Modified: ", 15 ) == 0 ) {
		sprintf( buf, "If-Modified-Since: %s", line+15 );
		NetWrite( nFile, buf, strlen(buf) );
		debug_logit( buf );
		break;
	    }
	}
	fclose( fp );
    }
      -------- ignore this feature -------- */

    /* Cookie: <cookie-value> */
    if( DataEntryQuery( srv->lpath, "cookie", line, sizeof(line) ) > 0 ) {
	sprintf( buf, "Cookie: %s\n", line );
	NetWrite( nFile, buf, strlen(buf) );
	debug_logit( buf );
    }

    ptr = "Accept: */*\n\n";
    NetWrite( nFile, ptr, strlen(ptr) );
    debug_logit( ptr );

    /* reply: HTTP/1.0 200 Document follows */
    NetGets( nFile, line, sizeof(line) );
    logit( line );
    if( (ptr = strchr( line, ' ' )) != NULL ) {
	ans = (int)strtol( ptr+1, (char**)0, 0 );
    }
    fputs( line, fout );
    while( (len = NetRead( nFile, line, sizeof(line) )) > 0 ) {
	fwrite( line, 1, len, fout );
    }
    NetClose( nFile );
    fclose( fout );
    return ans;
}

/*
 *name: HttpXferDir
 *	transfer URL as a directory
 */
int
HttpXferDir( srv, tmpfile )
struct server_info *srv;
char	*tmpfile;
{
    char	rpath[ STRLEN ];
    char	linkfile[ STRLEN ];
    char	*lpath = srv->lpath;
    int		ans;

    sprintf( rpath, "%s/", srv->rpath );
    sprintf( linkfile, "%s/._dir", lpath );
    ans = HttpXfer( srv, rpath, linkfile, tmpfile );
    if( ans < 300 ) {		/* 2xx Successful, 1xx Informational */
	if( chdir( lpath ) ) {
	    MakePath( linkfile );
	    if( chdir( lpath ) )
		return 404;		/* 404 Not Found */
	}
	HttpConvert( tmpfile, "index.html", "._dir" );
	symlink( srv->mitem->timeout, "._cache_time" );
    }
    return ans;
}

/*
 *name: HttpXferFile
 *	transfer URL as a text file
 */
int
HttpXferFile( srv, tmpfile )
struct server_info *srv;
char	*tmpfile;
{
    char	linkfile[ STRLEN ];
    char	*lpath = srv->lpath;
    char	*ptr;
    int		ans;

    if( (ptr = strrchr( lpath, '/' )) == NULL )
	return -1;
    *ptr = '\0';
    sprintf( linkfile, "%s/._dir.%s", lpath, ptr+1 );
    *ptr = '/';

    ans = HttpXfer( srv, srv->rpath, linkfile, tmpfile );
    if( ans < 300 ) {		/* 2xx Successful, 1xx Informational */
	MakePath( lpath );
	HttpConvert( tmpfile, lpath, linkfile );
    }
    return ans;
}

/*
 *name: HttpGetFile
 *	validate a URL file
 */
int
HttpGetFile( srv )
struct server_info *srv;
{
    char	tmpfile[ STRLEN ];
    char	*rpath, *ptr;
    int		ans;

    MakeTmpFile( srv->lpath, tmpfile, sizeof(tmpfile) );
    rpath = srv->rpath;
    if( (ptr = strrchr( rpath, '/' )) != NULL &&
	strcmp( ptr, "/index.html" ) == 0 ) {
	/* try get the directory html file (.../index.html) */
	*ptr = '\0';
	ptr = strrchr( srv->lpath, '/' );
	*ptr = '\0';
    }
    if( *rpath == '\0' || DashD( srv->lpath ) ) {
	ans = HttpXferDir( srv, tmpfile );
    } else if( DashF( srv->lpath ) ) {
	ans = HttpXferFile( srv, tmpfile );
    } else {
	ans = HttpXferFile( srv, tmpfile );
	if( ans >= 400 ) {		/* 4xx, 5xx (ex: 404 Not Found) */
	    return -1;
	} else if( ans >= 300 ) {	/* 3xx Redirection */
	    ans = HttpXferDir( srv, tmpfile );
	}
    }
    unlink( tmpfile );
    return( ans >= 400 ? -1 : 0 );
}

/*
 *name: HttpUserDef
 *	query/modify the extra header of http protocol.
 *	(ex: Cookie ...)
 */
int
HttpUserDef( srv, argc, argv )
struct server_info *srv;
int	argc;
char	*argv[];
{
    char	buf[ STRLEN ];
    char	*fpath, *key, *data;

    if( argc < 2 ) {
	sprintf( csusrmsg, "1 Usage: userdef local-path key (-|data)" );
	return 0;
    }
    fpath = argv[0];
    key = argv[1];
    if( argc < 3 ) {		/* query data */
	if( DataEntryQuery( fpath, key, buf, sizeof(buf) ) >= 0 ) {
	    sprintf( csusrmsg, "0 %s %s %s", fpath, key, buf );
	} else {
	    sprintf( csusrmsg, "1 %s %s not-found", fpath, key );
	}
    } else if( *argv[2] == '-' ) {	/* delete header */
	if( DataEntryDelete( fpath, key ) == 0 ) {
	    sprintf( csusrmsg, "0 %s %s deleted", fpath, key );
	} else {
	    sprintf( csusrmsg, "1 %s %s not-found", fpath, key );
	}
    } else {
	data = argv[2];
	DataEntryInsert( fpath, key, data, strlen(data)+1 );
	sprintf( csusrmsg, "0 %s %s inserted", fpath, key );
    }
    return 0;
}

int
HttpNop()
{
    return 0;
}

int
HttpInit( tbl )
struct agent_item	*tbl;
{
    tbl->localdata	= (char *) &HttpData;
    tbl->connect	= HttpNop;
    tbl->disconnect	= HttpNop;
    tbl->listdents	= HttpGetFile;
    tbl->getfile	= HttpGetFile;
    tbl->putfile	= HttpNop;
    tbl->userdef	= HttpUserDef;
    return 0;
}

