/*
** init.c for Inet-Module
** Initialisation for HTML.APP browser inet-module
**
** Copyright (C) 1995-1996, Andrew 'Dancer' Vesperman. All rights reserved.
** Portions Copyright (C) 1995, Stephane Boisson. All Rights reserved.
** Login <boisson@worldnet.net>
**
** Started on  Sun Aug 27 23:41:30 1995 Stephane Boisson
** Last update Mon Aug 28 00:44:10 1995 Stephane Boisson
** Dancer commenced on 31 Dec 1995
** Last update 4 Jan 1995
** hyc commenced 12 Apr 1997
**
** This file can be redistributed under the terms of the GNU General
** Public Licence.
*/

#include <unistd.h>
#include "module.h"

#include <osbind.h>
#include <mintbind.h>
#include <basepage.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <netdb.h>
#include <fcntl.h>
#include <setjmp.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include "hostinfo.h"
#include "weblib.h"

/*--- Prototypes ---*/
long            ___CDECL
init_module(url_methods_t * out, browser_info_t * in, char *path);
void            ___CDECL
restore_module(void);
void            myloop();
void            ___CDECL
get_version(char **authorp, long *versionp, long *datep);

/*--- Global variables ---*/
browser_info_t *browser;
char          **proxies;
char            cab_version[6];

long            child;
int             ifd, ofd, ap_id;

int             errno;
int             __mint;		/* 0 for TOS, MiNT version number otherwise */
FILE _iob[_NFILE];		/* stream buffers initialized below */
size_t __DEFAULT_BUFSIZ__;
char          **environ;
short           _split_mem;
long            _stksize = 48 * 1024L;
void           *_heapbase;
BASEPAGE       *_base;

char            _rootdir;

/* Pexec entry point */
startup(BASEPAGE * b)
{
    if (__mint)
    {
	register long   hitpa;
	hitpa = (long) b->p_hitpa;
	__asm__ volatile ("movl %0,sp"::"r" (hitpa));
	myloop();
    }
    Pterm0();
}

static const long magic[] = {BROWSER_MAGIC1, BROWSER_MAGIC2,
		     BROWSER_MAGIC3, BROWSER_MAGIC4BIS, (long) init_module};

/*
 * get MiNT version number.
 */
static long     getMiNT 
__PROTO((void));

static long 
parseenv(BASEPAGE * bp);

static long
getMiNT()
{
    long           *cookie;

    cookie = *((long **) 0x5a0L);
    if (!cookie)
	__mint = 0;
    else
    {
	while (*cookie)
	{
	    if (*cookie == 0x4d694e54L)
	    {			/* MiNT */
		__mint = (int) cookie[1];
		return 0;
	    }
	    cookie += 2;
	}
    }
    __mint = 0;
    return 0;
}

/* ----------------------------------------------------------------- **
** init_module - Initialize the module (called by browser)           **
** ----------------------------------------------------------------- */
long            ___CDECL
init_module(out, in, path)
    url_methods_t  *out;	/* struture to fill */
    browser_info_t *in;		/* infos about browser */
    char           *path;	/* module path, '\' terminated */
{
    char           *c, *d;
    int             i;
    long            m, n;

    /*--- Set browser info variable ---*/
    browser = in;

    /*--- Fill URL methods structure ---*/
    out->restore = restore_module;
    out->get_url = get_url;
    out->get_url_info = get_url_info;
    out->get_version = get_version;
    out->post = post;
    out->mailto = mailto;
    out->get_url_if_modified = get_if_newer;

    /*--- Initialize other stuffs here ---*/
    c = (char *) &browser->version;
    d = cab_version;
    if (*c != '0')
	*d++ = *c;
    c++;
    *d++ = *c++;
    *d++ = '.';
    *d++ = *c++;
    *d++ = *c++;
    *d = '\0';

    proxies = (char **)browser->proxy;

    _base = (BASEPAGE *) browser->basepage;
    m = parseenv(_base);
/* make m the total number of bytes required by program sans stack/heap */
    m += (_base->p_tlen + _base->p_dlen + _base->p_blen + sizeof(BASEPAGE));
    m = (m + 3L) & (~3L);

/* m takes into account the first process. Now we add space for the forked
 * process' basepage, then our initial heap, and then the forked proc's
 * stack.
 */
    _stksize &= (~3L);
    n = _stksize + 8192;
    Mshrink(_base, m + n);
    _heapbase = (void *) ((long) _base + m);

    _init_signal();
/*
 * check for MiNT
 */
    (void) Supexec(getMiNT);
    if (!__mint)
	return (0);

    (void) Pdomain(1);		/* set MiNT domain */

    __DEFAULT_BUFSIZ__ = 4096;
    _rootdir = 'u';

    stdin->_flag = _IOREAD | _IOFBF;
    stdin->_file = 0;
    stdout->_flag = _IOWRT | _IOLBF;
    stdout->_file = 1;
    stderr->_flag = _IORW | _IONBF;
    stderr->_file = 2;

    {
	short           fds[2];
	if (Fpipe(fds) < 0)
	    return 0;
	ofd = fds[1];
	ifd = fds[0];
    }
    browser->aes_crystal();
    ap_id = browser->aes_global[1] >> 16;

    /* Set hitpa, child will use this for top of stack */
    _base->p_hitpa = ((char *) _base) + m + n;
    if ((child = Pexec(104, 0L, _base, 0L)) < 0)
	return 0;

    Fclose(ifd);

    /*--- Return support ---*/

    m = SUPPORT_HTTP /* |SUPPORT_FTP|SUPPORT_GOPHER|SUPPORT_WAIS */ ;
    if (browser->proxy->ftp_proxy)
	m |= SUPPORT_FTP;
    if (browser->proxy->wais_proxy)
	m |= SUPPORT_WAIS;
    if (browser->proxy->gopher_proxy)
	m |= SUPPORT_GOPHER;
    if (browser->proxy->smtp_server)
	m |= SUPPORT_MAILTO;
    if (browser->proxy->nntp_server)
	m |= SUPPORT_NNTP;
    return (SUPPORT_HTTP | SUPPORT_FTP | SUPPORT_MAILTO | SUPPORT_GOPHER |
	    SUPPORT_NNTP);
}


/* ----------------------------------------------------------------- **
** get_version - Returns infos about module                          **
** ----------------------------------------------------------------- */
void            ___CDECL
get_version(authorp, versionp, datep)
    char          **authorp;	/* 4x30 chars separated by '|' */
    long           *versionp;	/* Version number in BCD format (V1.15 ->
				 * 0x00011500) */
    long           *datep;	/* Date in BCD format (0xYYYYMMDD) */
{
    char           *ptr = (char *) datep;

    *versionp = version_bcd;

    *ptr++ = (date[7] & 0x0f) << 4 | (date[8] & 0x0f);
    *ptr++ = (date[9] & 0x0f) << 4 | (date[10] & 0x0f);

    switch (date[2])
    {
    case 'n':
	if (date[1] == 'a')
	    *ptr++ = 0x01;
	else
	    *ptr++ = 0x06;
	break;
    case 'b':
	*ptr++ = 0x02;
	break;
    case 'r':
	if (date[1] == 'a')
	    *ptr++ = 0x03;
	else
	    *ptr++ = 0x04;
	break;
    case 'y':
	*ptr++ = 0x05;
	break;
    case 'l':
	*ptr++ = 0x07;
	break;
    case 'g':
	*ptr++ = 0x08;
	break;
    case 'p':
	*ptr++ = 0x09;
	break;
    case 't':
	*ptr++ = 0x10;
	break;
    case 'v':
	*ptr++ = 0x11;
	break;
    case 'c':
	*ptr++ = 0x12;
	break;
    default:
	*ptr++ = 0x00;
	break;
    }
    *ptr++ = (date[4] & 0x0f) << 4 | (date[5] & 0x0f);

    *authorp = (char *) when;
}


/* ----------------------------------------------------------------- **
** restore_module - De-initialization                                **
**                  (freeing memory, closing files, etc...)          **
** ----------------------------------------------------------------- */
void            ___CDECL
restore_module()
{
    Pkill(child, SIGTERM);
    Pwait();
}


asm(".stabs \"_exit\",5,0,0,_bye");
asm(".stabs \"__exit\",5,0,0,_bye");
void 
bye(int status)
{
    Pterm(status);
}

/*
 * parseenv(bp): parse the environment pointed to by the
 * basepage. Return the number of bytes of environment
 * that have been appended to the bss area (the environ and argv arrays
 * are put here, as is a temporary buffer for the command line, if
 * necessary).
 *
 * The MWC extended argument passing scheme is assumed.
 *
 */

static long 
parseenv(bp)
    BASEPAGE       *bp;
{
    long            count = 4;	/* compensate for aligning */
    long            i;
    char           *from, *to;
    char          **envp;
/* flag to indicate desktop-style arg. passing */
    long            desktoparg;

/* handle the environment first */

    environ = envp = (char **) (((long) bp->p_bbase + bp->p_blen + 4) & (~3));
    from = bp->p_env;
    while (*from)
    {

/* if we find MWC arguments, tie off environment here */
	if (*from == 'A' && *(from + 1) == 'R' && *(from + 2) == 'G' &&
	    *(from + 3) == 'V' && *(from + 4) == '=')
	{
	    *envp++ = (char *) 0;
	    count += 4;
	    *from = 0;
#ifdef STRICTLY_COMPATIBLE_WITH_STANDARD
	    if (bp->p_cmdlin[0] != 127)
		goto old_cmdlin;
#endif
	    break;
	}
	*envp++ = from;
	count += 4;
	desktoparg = 1;
	while (*from)
	{
	    if (*from == '=')
	    {
		desktoparg = 0;
	    }
	    from++;
	}
	from++;			/* skip 0 */

/* the desktop (and some shells) use the environment in the wrong
   way, putting in "PATH=\0C:\0" instead of "PATH=C:". so if we
   find an "environment variable" without an '=' in it, we
   see if the last environment variable ended with '=\0', and
   if so we append this one to the last one
 */
	if (desktoparg && envp > &environ[1])
	{
	    /* launched from desktop -- fix up env */
	    char           *p, *q;

	    q = envp[-2];	/* current one is envp[-1] */
	    while (*q)
		q++;
	    if (q[-1] == '=')
	    {
		p = *--envp;
		while (*p)
		    *q++ = *p++;
		*q = '\0';
	    }
	}
    }
    *envp++ = (char *) 0;
    count += 4;
    return count + 4;
}

void
_fclose_all_files()
{
    register int    i, f;

    for (i = 0; i < _NFILE; ++i)
    {
	f = _iob[i]._flag;
	if (f & (_IORW | _IOREAD | _IOWRT))
	    if (_iob[i]._file <= 2)	/* only flush std. streams */
		fflush(&_iob[i]);
	    else
		fclose(&_iob[i]);
    }
}
