/* Copyright 1997 Acorn Computers Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/***************************************************/
/* File   : Meta.c                                 */
/*                                                 */
/* Purpose: Handling META tags.                    */
/*                                                 */
/* Author : A.D.Hodgkinson                         */
/*                                                 */
/* History: 25-Jul-97: Created.                    */
/***************************************************/

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

#include "swis.h"
#include "flex.h"

#include "HTMLLib.h" /* HTML library API, Which will include html2_ext.h, tags.h and struct.h */

#include "wimp.h"
#include "wimplib.h"
#include "event.h"

#include "svcprint.h"
#include "Global.h"
#include "Utils.h"

#include "Browser.h"
#include "FetchPage.h"
#include "URLutils.h"

#include "Meta.h"

/* Static function prototypes */

static _kernel_oserror * meta_process_refresh(browser_data * b, HStream * t, const char * content);

/*************************************************/
/* meta_process_tag()                            */
/*                                               */
/* In HTML, META tags can contain a great        */
/* variety of information (so much so that this  */
/* source file is entirely dedicated to them).   */
/* This function is the entry point for dealing  */
/* with a new META tag.                          */
/*                                               */
/* Parameters: Pointer to a browser_data struct  */
/*             relevant to the token stream      */
/*             holding the META tag;             */
/*                                               */
/*             Pointer to the token representing */
/*             the META tag.                     */
/*************************************************/

_kernel_oserror * meta_process_tag(browser_data * b, HStream * t)
{
  const char * name;
  const char * equiv;
  const char * content;
  const char * scheme;

  if (!t || !b) return NULL;

  /* Extract information from the token */

  name    = HtmlMETAname      (t);
  equiv   = HtmlMETAhttp_equiv(t);
  content = HtmlMETAcontent   (t);
  scheme  = HtmlMETAscheme    (t);

  /* Work out what to do */

  if (!utils_strcasecmp(equiv, "refresh"))
  {
    /* Refresh - load a new page or reload the current page */
    /* after a certain amount of time                       */

    if (choices.client_pull)
    {
      return meta_process_refresh(b, t, content);
    }
  }

  return NULL;
}

/*************************************************/
/* meta_process_refresh()                        */
/*                                               */
/* Handles META tags specify that a page         */
/* refresh (reload) should occur at some time.   */
/*                                               */
/* Parameters: Pointer to a browser_data struct  */
/*             relevant to the META tag;         */
/*                                               */
/*             The content string for the tag.   */
/*************************************************/

static _kernel_oserror * meta_process_refresh(browser_data * b, HStream * t, const char * content)
{
  _kernel_oserror * e;
  char            * separator;
  int               time_now;

  if (!content || !b) return NULL;

  /* See if there's any URL specified - else it's the current page that is to be refetched */

  separator = strchr(content, ';');
  if (!separator) separator = strchr(content, ',');

  /* If we found a separator, skip white space */

  if (separator)
  {
    separator ++;

    while (*separator && *separator < 33) separator++;

    if (!*separator) separator = NULL;
    else
    {
      int success = 0;

      /* May have a 'url=' before the actual URL, */
      /* or 'name=' in some broken examples...    */

      if      (!utils_strncasecmp(separator, "url",  3)) success = 3;
      else if (!utils_strncasecmp(separator, "name", 4)) success = 4;

      if (success)
      {
        char * oldsep = separator;

        separator += success;

        /* Skip any white space */

        while (*separator && *separator < 33) separator++;

        /* Should be at an '='; if not, sssume 'url' was the URL to fetch! */

        if (*separator != '=') separator = oldsep;
        else
        {
          /* Skip the '=' and any more white space */

          separator ++;
          while (*separator && *separator < 33) separator++;

          /* Should be at the URL now, but make sure... */

          if (!*separator) separator = NULL;
        }
      }
    }
  }

  /* Work out the URL to fetch */

  b->meta_refresh_url = HtmlRelativiseURL(browser_current_url(b),
                                          separator ? separator : "",
                                          t);

  /* Only proceed if HtmlRelativiseURL didn't fail */

  if (b->meta_refresh_url)
  {
    /* Work out what time to fetch at */

    e = _swix(OS_ReadMonotonicTime,
              _OUT(0),

              &time_now);

    if (e) return e;

    b->meta_refresh_at = -atoi(content); /* Mark this as 'pending' with a value <= 0 */

    /* Install the handler */

    register_null_claimant(Wimp_ENull, (WimpEventHandler *) meta_check_refresh, b);
  }

  return NULL;
}

/*************************************************/
/* meta_check_refresh()                          */
/*                                               */
/* After a META tag specifying a page (re)load   */
/* (refresh) has been processed, this null       */
/* handler will initiate the appropriate fetch   */
/* after the appropriate delay.                  */
/*                                               */
/* Paramters are as standard for a Wimp event    */
/* handler.                                      */
/*************************************************/

int meta_check_refresh(int eventcode, WimpPollBlock * b, IdBlock * idb, browser_data * handle)
{
  int time_now;

  /* Nothing to do if we're still fetching */

  if (handle->anim_handler) return 0;

  /* Otherwise, check the current time */

  _swix(OS_ReadMonotonicTime,
        _OUT(0),

        &time_now);

  /* If we've stopped fetching, change the refresh field from */
  /* <= 0 to show 'pending' to an actual time when the new    */
  /* fetch should start.                                      */

  if (handle->meta_refresh_at <= 0)
  {
    handle->meta_refresh_at = (100 * -handle->meta_refresh_at) + time_now; /* ('* 100' for seconds -> centiseconds) */
  }

  /* Exit if we haven't reached the fetch time */

  if (time_now < handle->meta_refresh_at) return 0;

  /* Otherwise, deregister this handler and start the fetch */

  deregister_null_claimant(Wimp_ENull, (WimpEventHandler *) meta_check_refresh, handle);
  handle->meta_refresh_at = 0;

  /* If we're on the same page, force an uncached fetch - NB, if */
  /* you don't set reloading you'll need to modify the top of    */
  /* fetchpage_preprocessed where it deals with checking for a   */
  /* fragment (jump to a named anchor). Otherwise client pull on */
  /* sites such as http://jupiter.beseen.com/chat/rooms/g/1678/  */
  /* will fail.                                                  */

  if (
       browser_current_url(handle) &&
       !urlutils_urlsscmp(handle->meta_refresh_url,
                          browser_current_url(handle))
     )
     handle->reloading = 1;

  ChkError(fetchpage_new(handle,
                         handle->meta_refresh_url,
                         1,
                         0));

  handle->meta_refresh_url = NULL;

  return 0;
}

/*************************************************/
/* meta_cancel_refresh()                         */
/*                                               */
/* Cancels any registered null handler to deal   */
/* with client pull (through                     */
/* META HTTP-EQUIV="Refresh").                   */
/*                                               */
/* Does not clear the browser-local 'client      */
/* pull' flag.                                   */
/*                                               */
/* Parameters: Pointer to a browser_data struct  */
/*             relevant to the handler.          */
/*************************************************/

void meta_cancel_refresh(browser_data * b)
{
  if (b->meta_refresh_url && b->meta_refresh_at)
  {
    deregister_null_claimant(Wimp_ENull, (WimpEventHandler *) meta_check_refresh, b);

    b->meta_refresh_at  = 0;
    b->meta_refresh_url = NULL;
  }
}