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

#if defined(__OS2__)
#include <io.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <types.h>
#endif

#if defined(__NT__)
#include <io.h>
#include <winsock.h>
#define soclose closesocket
#endif

#if defined(__UNIX__)
#include <unistd.h>
#include <fcntl.h>
#include <pwd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#if defined(__SOL__) || defined(__LINUX__)
#include <sys/types.h>
#include <netinet/in.h>
#endif
#define soclose close
#endif

#define PK_TCPIP_CONST_MAXTCPIP_SEND  (1024 *31)

#ifndef min
#define min(x,y) ((x) > (y) ? (y) : (x))
#endif

int Verbose = 0 ;

#define Send(x,y)    MySend(x,y,strlen(y));
#define Recv(x,y,z)  MyRecv(x,y,z)

int MySend(int fd, char *buffer, unsigned long len) {
    unsigned long    numThisTime ;
    unsigned long    rc = 0 ;
    unsigned long    total = 0 ;
    char            *ptr = buffer ;

    if (Verbose) printf("%s", buffer);
    while( len ) {
        numThisTime = min(len, PK_TCPIP_CONST_MAXTCPIP_SEND);
        rc = send( fd, ptr, numThisTime, MSG_DONTROUTE );
        if ( rc == -1 ) return( -1 );
        total += rc ;
        ptr += rc ;
        len -= rc ;
    }
    return( total );
}

int MyRecv(int fd, char *buffer, unsigned long len) {
    unsigned long   numThisTime ;
    unsigned long   rc = 0 ;
    unsigned long   total = 0 ;
    char           *ptr = buffer ;

    while( len ) {
        numThisTime = min(len, PK_TCPIP_CONST_MAXTCPIP_SEND);
        rc = recv( fd, ptr, numThisTime, 0 );
        if ( rc == -1 ) return( -1 );
        total += rc ;
        if ( rc != numThisTime ) break ;
        ptr += rc ;
        len -= rc ;
    }
    return( total );
}

char *Encode(char *ptr) {
    static char buffer[255];
    static char base64[] = {
        65,  66,  67,  68,  69,  70,  71,  72,  // "ABCDEFGH"
        73,  74,  75,  76,  77,  78,  79,  80,  // "IJKLMNOP"
        81,  82,  83,  84,  85,  86,  87,  88,  // "QRSTUVWX"
        89,  90,  97,  98,  99, 100, 101, 102,  // "YZabcdef"
       103, 104, 105, 106, 107, 108, 109, 110,  // "ghijklmn"
       111, 112, 113, 114, 115, 116, 117, 118,  // "opqrstuv"
       119, 120, 121, 122,  48,  49,  50,  51,  // "wxyz0123"
        52,  53,  54,  55,  56,  57,  43,  47   // "456789+/"
    };

    int length = strlen(ptr);
    int in=0, out=0 ;
    char ch1, ch2, ch3 ;

    while ( length >= 3 ) {
        ch1 = ptr[in++];
        ch2 = ptr[in++];
        ch3 = ptr[in++];
        length -= 3 ;
        buffer[out++] = base64[ ch1 >> 2 ];
        buffer[out++] = base64[ ((ch1 & 0x3) << 4) | (ch2 >> 4) ];
        buffer[out++] = base64[ ((ch2 & 0xf) << 2) | (ch3 >> 6) ];
        buffer[out++] = base64[ ch3 & 0x3f ];
    }
    switch( length ) {
        case 0: break ;
        case 1:
        case 2: ch1 = ptr[in++];
                ch2 = (length == 2 ? ptr[in] : 0 );
                buffer[out++] = base64[ch1 >> 2];
                buffer[out++] = base64[(ch1 & 0x3) << 4 | ch2 >> 4];
                if ( length == 2 )  buffer[out++] = base64[ (ch2 & 0xf) << 2];
                else                buffer[out++] = 61 ;
                buffer[out++] = 61 ;
                break ;
    }
    buffer[out] = 0 ;
    return( buffer );
}

int Connect( char *hostName, int portNumber )
{
       struct sockaddr_in  address;
       struct hostent     *host;
       int                     fd ;

       memset((char*)&address, 0, sizeof(address));
       address.sin_family      = AF_INET ;
       address.sin_addr.s_addr = inet_addr( hostName );
       address.sin_port        = htons( portNumber );

       /*----------------------------------------------+
       | Initialize the socket interface.              |
       +----------------------------------------------*/
#if __NT__
       WORD     wVersionRequested;
       WSADATA  wsaData;
       wVersionRequested = MAKEWORD(1,1);
       WSAStartup(wVersionRequested,&wsaData);
#elif __OS2__
       sock_init();
#endif

       if (!(host = gethostbyname(hostName)))
           exit(printf("Cant' find host '%s'\n", hostName ));
       else
         memcpy((char*)&address.sin_addr, host->h_addr, host->h_length);

       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
           exit(printf("Can't open socket\n"));

       if (connect(fd, (struct sockaddr *)&address, sizeof(address)) == -1)
           exit(printf("Can't connect to %s@%d\n", hostName, portNumber ));
       return  fd ;
}

int main(int argc, char *argv[])
{
    char  *prog = argv[0] ;
    char  *verb = NULL ;
    char  *url  = NULL ;
    char  *file = NULL ;
    int    count = 0 ;
    int    len, portNum, fd ;
    int    help = 0 ;
    char   buffer[1024], *ptr ;
    char   host[255] ;

    for ( argv++ ; *argv ; argv++ ) {
        if ( **argv == '-' ) {
            for ( (*argv)++ ; **argv ; (*argv)++ )
                switch( **argv ) {
                    case 'v':
                    case 'V': Verbose++ ; break ;
                    default : help = 1 ; break ;
                };
        }
        else
            switch( count++ ) {
                case 0 : verb = *argv ; break ;
                case 1 : url  = *argv ; break ;
                case 2 : file = *argv ; break ;
                default: help = 1 ; break ;
            }
    }

    if ( argc < 3 || help )
        exit( printf("\nUsage: %s [-v] verb url [file]\n"
                     "         'file' is sent only is verb is PUT\n",
                     prog ) );

    if ( getenv("TC_USER") == NULL )
        exit( printf("TC_USER must be set\n") );

    if ( strncmp(url, "http://",7) )
        exit(printf("Only http is supported\n"));

    ptr = url + 7 ;
    for ( ptr = url + 7 ; *ptr && *ptr != ':' && *ptr != '/' ; ptr++ );
    strncpy( host, url+7, ptr-url-7 );
    host[ptr-url-7] = 0 ;
    portNum = atoi(++ptr);
    if ( portNum == 0 ) portNum = 80 ;
    while ( *ptr && *ptr != '/'  ) ptr++ ;
    if ( *ptr == '\0' ) *ptr = '/' ;

    fd = Connect( host, portNum );
    if ( Verbose )
        printf("Sending\n-----------------------------------------------------\n");
    sprintf( buffer, "%s %s HTTP/1.1\n", verb, ptr);
    Send( fd, buffer );
    sprintf( buffer, "Host: %s:%d\n", host, portNum );
    Send( fd, buffer );
    sprintf( buffer, "%s:", getenv("TC_USER") );
    sprintf( buffer, "Authorization: Basic %s\n", Encode(buffer) );
    Send( fd, buffer );
    Send( fd, "Content-Type: text/xml\n" );

    if ( (!strcmp(verb, "store")) || (!strcmp(verb, "put")) ) {
        char *buf = NULL ;
        unsigned long len = 0, size = 0 ;
        int           rc ;
        FILE *fp = fopen( file, "r" );
        if ( !fp ) exit( printf("Can't open '%s'\n", file ) );
        while ( !feof(fp) ) {
            if ( len+1024 >= size )
                buf = (char*) realloc( buf, size += 1024 );
            rc = fread( buf+len, 1, 1024, fp );
            if ( !rc ) break ;
            len += rc ;
        }
        fclose(fp);
        sprintf( buffer, "Content-Length: %d\n\n", len );
        Send( fd, buffer );
        MySend( fd, buf, len );
        free( buf );
    }
    else
        Send( fd, "\n" );

    if ( Verbose )
        printf("Receiving\n-----------------------------------------------------\n");
    while ( (len = Recv(fd, buffer, 1023)) > 0 ) {
        buffer[len] = '\0' ;
        printf( "%s", buffer );
    }
    soclose( fd );
    return( 0 );
}
