/* http component for RISC OS version of LANModemM
   Purpose:
           Get IP number from LANModem stats page
           Instigate call
           Instigate hangup
           Set IP at dynamicdns.org
*/

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

#include "oslib/url.h"
#include "werr.h"

extern os_error *e ;

/* Global variables for URL session - we have just one */
url_s session ;
url_fetch_status status  =  0 ;
char *body = NULL ;
int body_alloc = 0 ;


static void
http_get_failure(os_error *err)
{
  url_deregister(0, session) ;
  if (err) werr(0, err->errmess) ;
  status = -1 ;
}

static int
url_grow_body(int extra)
{
  body = realloc(body, body_alloc + extra) ;
  if (!body)
  {
    werr(0, "Memory allocation failed") ;
    http_get_failure(NULL) ;
    return -1 ; /* Failed */
  }

  body_alloc += extra ;

  return 0 ; /* Ok */
}
/* Start an http fetch, calling pollfunc until completed */

char *
http_get_url(char *url,
             char *proxy,
             int (*pollfunc)(void *),
             void *user_data)
{
  os_t end_t ;
  int reply_size = 0 ;

  /* Register with URL module */

  e = xurl_register(0, &session) ;
  if (e)
  {
    werr(0, e->errmess) ;
    return "" ;
  }

  if (proxy)
  {
    /* Enable the proxy */

    e = xurl_set_proxy__enable(0,
                               session,
                               proxy,
                               "http:",
                               &status) ;
    if (e)
    {
      http_get_failure(e) ;
      return "" ;
    }
  }

  /* Request the URL */

  e = xurl_get_url(url_GET_URL_USER_AGENT_SUPPLIED,
                   session,
                   url_GET,
                   (char const *) url,
                   (byte const *) "GET / HTTP1.0",
                   2,
                   (char const *) "LANModemM",
                   &status) ;

  if (e)
  {
    http_get_failure(e) ;
    return "" ;
  }

  /* Set for 10-s timeout */
  end_t = 1000 + os_read_monotonic_time() ;

  /* Wait for status to change */

  if ((status != url_CONNECTED) && (status != 0))
  {
    http_get_failure(NULL) ;
    werr(0, "Error: xurl_get_url failed") ;
    return "" ;
  }

  /* Reset body text variables */
  if (!body)
    if (-1 == url_grow_body(2560)) return "" ;

  body[0] = '\0' ;

  /* Call xurl_read_data until we have everything */
  while (status != url_ALL_DATA_RECEIVED)
  {
    /* Get 256 bytes at a time */
    int bytes_read, bytes_remaining ;
    char buffer[256] ;

    do
    {
      e = xurl_read_data(
        0,
        session,
        (byte *) buffer,
        255,
        &status,
        &bytes_read,
        &bytes_remaining) ;

      if (e)
      {
        http_get_failure(e) ;
        return "" ;
      }

     /* Did we get anything? */
      if (bytes_read > 0)
      {
        /* Grow body space if need be, in chunks of buffer length */
        if (reply_size + 1 + bytes_read >= body_alloc)
        {
          /* Allocate more memory */
          if (-1 == url_grow_body(256)) return "" ;
        }

        memcpy(&body[reply_size], buffer, bytes_read) ;
        reply_size += bytes_read ;
        body[reply_size] = '\0' ;
      }

      if (os_read_monotonic_time() > end_t)
      {
        http_get_failure(NULL) ;
        werr(0, "Timeout reading URL response") ;
        return "" ;
      }
    } while (bytes_remaining > 0) ;

    if (os_read_monotonic_time() > end_t)
    {
      http_get_failure(NULL) ;
      werr(0, "Timeout reading URL response") ;
      return "" ;
    }
    if (pollfunc)
      if (-1 == pollfunc(user_data)) exit(0) ;
  }

  return body ;
}
