/*
 *  http.c
 *  Some simple routines for connecting to a remote tcp socket
 *  Copyright 1999 Håvard Kvålen <havardk@sol.no>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/* FIXME: We need to have *one* place in xmms where you configure proxies */

#include "http.h"

gint
http_open_connection(const gchar * server, gint port)
{
    gint sock;
    struct hostent *host;
    struct sockaddr_in address;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    address.sin_family = AF_INET;

    if (!(host = gethostbyname(server)))
        return 0;

    memcpy(&address.sin_addr.s_addr, *(host->h_addr_list),
           sizeof(address.sin_addr.s_addr));
    address.sin_port = g_htons(port);

    if (connect
        (sock, (struct sockaddr *) &address,
         sizeof(struct sockaddr_in)) == -1)
        return 0;

    return sock;
}

void
http_close_connection(gint sock)
{
    shutdown(sock, 2);
    close(sock);
}

gint
http_read_line(gint sock, gchar * buf, gint size)
{
    gint i = 0;

    while (i < size - 1) {
        if (read(sock, buf + i, 1) <= 0) {
            if (i == 0)
                return -1;
            else
                break;
        }
        if (buf[i] == '\n')
            break;
        if (buf[i] != '\r')
            i++;
    }
    buf[i] = '\0';
    return i;
}

gint
http_read_first_line(gint sock, gchar * buf, gint size)
{
    /* Skips the HTTP-header, if there is one, and reads the first line into buf.
       Returns number of bytes read. */

    gint i;
    /* Skip the HTTP-header */
    if ((i = http_read_line(sock, buf, size)) < 0)
        return -1;
    if (!strncmp(buf, "HTTP", 4)) { /* Check to make sure its not HTTP/0.9 */
        while (http_read_line(sock, buf, size) > 0)
            /* nothing */ ;
        if ((i = http_read_line(sock, buf, size)) < 0)
            return -1;
    }

    return i;
}

gchar *
http_get(gchar * url)
{
    gchar *server, *getstr, *buf = NULL, *bptr;
    gchar *gs, *gc, *turl = url;
    gint sock, n, bsize, port = 0;

    /* Skip past ``http://'' part of URL */
    if (!strncmp(turl, "http:", 5)) {
        turl += 5;
        if (!strncmp(turl, "//", 2))
            turl += 2;
    }

    /* If path starts with a '/', we are referring to localhost */
    if (turl[0] == '/')
        server = "localhost";
    else
        server = turl;

    /* Check if URL contains port specification */
    gc = strchr(turl, ':');
    gs = strchr(turl, '/');

    if (gc != NULL && gc < gs) {
        port = atoi(gc + 1);
        *gc = '\0';
    }
    if (port == 0)
        port = 80;

    /* Make sure that server string is null terminated. */
    if (gs)
        *gs = '\0';


    /*
     * Now, open connection to server.
     */
    sock = http_open_connection(server, port);

    /* Repair the URL string that we broke earlier on */
    if (gs)
        *gs = '/';
    if (gc && gc == '\0')
        *gc = ':';

    if (sock == 0)
        return NULL;

    /*
     * Send query to socket.
     */
    getstr = g_strdup_printf("GET %s HTTP/1.0\r\n\r\n", gs ? gs : "/");
/*  	getstr = g_strdup_printf("GET %s HTTP/1.0\r\n\r\n", url ? url : "/"); */

    if (write(sock, getstr, strlen(getstr)) == -1) {
        http_close_connection(sock);
        return NULL;
    }

    /*
     * Start receiving result.
     */
    bsize = 4096;
    bptr = buf = g_malloc(bsize);

    if ((n = http_read_first_line(sock, bptr, bsize)) == -1) {
        g_free(buf);
        buf = NULL;
        goto Done;
    }

    bsize -= n;
    bptr += n;

    while (bsize > 0 && (n = http_read_line(sock, bptr, bsize)) != -1) {
        bptr += n;
        bsize -= n;
    }

  Done:
    http_close_connection(sock);

    /*
     * Return result buffer to caller.
     */
    return buf;
}
