/*
** GrabHTTP.h
** Copyright (C) 1996-97 Serge Emond
**
** 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.
*/

#include "GrabHTTP.h"
#include "GHWindows_protos.h"

/// Prototypes
#include "GHRexxFcts_protos.h"
#include "GHUtilities_protos.h"
#include "GHBase64.h"
void EndAll(ULONG);
///

/// Externs

extern const TEXT *version;
extern struct Common c;
extern struct Specific s;

extern const struct Functions fcts[];

///

/// exe_GetByteRecd
// Returns last bytes received in GHRES

void exe_GetByteRecd(TEXT *p)
{
    TEXT ret[12];
    
    stcul_d(ret, s.recd);
    Reply(NULL, ret);
}
///

/// exe_GetCPS
// Returns last transfer's CPS

void exe_GetCPS(TEXT *p)
{
    TEXT ret[12];
    
    stcul_d(ret, s.cps);
    Reply(NULL, ret);
}
///

/// exe_GetHeaderString

#define GetHeaderString_Opts "STRING"

void exe_GetHeaderString(TEXT *p)
{
    struct RDArgs rda;
    LONG opts[1];
    struct MemNode *tnode;

    opts[0] = (LONG) "HTTP/1.0";

    if (!ReadAVar(fcts[c.CurFct].temp, opts, &rda, p)) Reply(5, NULL);
    else
    {
        if (tnode = SearchMemListHeader((struct MemNode *)&s.memlst,
            (TEXT *)opts[0], strlen((TEXT *)opts[0]))) {

            Reply(0, (TEXT *)tnode->p);
        }
        else
            Reply(1, NULL);
        FreeArgs(&rda);
    }
}
///

/// exe_GetHTTPFile

/*
** URL/A         (string)
**       URL to grab
** FILENAME/K    (string)
**       Filename to save url to
** MAXSIZE/N     (string)
**       Maximal size of the file
** HEADERONLY/S  (BOOL)
**       Don't get the file - only the header
** IFMODIFIED/S  (BOOL)
**       Only grab if modified
** PROGRESS/S    (BOOL)
**       Display progress info
** SAVEHEADER/S  (BOOL)
**       Save header to disk
** TOUCHDIRS/S   (BOOL)
**       Touch old dirs (set date)
**
** RC
**   0   Return Code is in GHRES
**   5   Failed to parse args
*/

#define GetHTTPFile_Opts "URL/A,FILENAME/K,MAXSIZE/N,HEADERONLY/S," \
                         "IFMODIFIED/S,PROGRESS/S,SAVEHEADER/S,TOUCHDIRS/S"

void exe_GetHTTPFile(TEXT *p)
{
    struct RDArgs rda;
    LONG opts[8]={NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
    LONG ret;
    TEXT rets[13];
    
    if (!ReadAVar(fcts[c.CurFct].temp, opts, &rda, p)) Reply(5, NULL);
    else
    {
        ret = GetHTTPFile((TEXT *)opts[0], (opts[1]?(TEXT *)opts[1]:NULL),
                (opts[2]?*((ULONG *)opts[2]):NULL),
                opts[3], opts[4], opts[5], opts[6], opts[7]);
        stcl_d(rets, ret);
        Reply(NULL, rets);
        FreeArgs(&rda);
    }
}
///

/// exe_GetSize

void exe_GetSize(TEXT *p)
{
    TEXT ret[12];
    
    stcul_d(ret, s.size);
    Reply(NULL, ret);
}
///

/// exe_GetTicks

void exe_GetTicks(TEXT *p)
{
    TEXT ret[12];
    
    stcul_d(ret, s.totticks);
    Reply(NULL, ret);
}
///

/// exe_Quit

void exe_Quit(STRPTR p)
{
    Reply(NULL, NULL);
    EndAll(NULL);
}
///

/// exe_SetAuth

/*
** USERKEY  (string)
**      If "USERKEY" if not given, authorization is cleared.
**      -> "login:password"
**
** RC
**   0   Done
**   1   Failed to alloc mem to store Auth
**   5   ...
*/

#define SetAuth_Opts "USERKEY"

void exe_SetAuth(TEXT *p)
{
    struct RDArgs rda;
    LONG opts[1]={NULL};
    TEXT *key;
    
    if (!ReadAVar(fcts[c.CurFct].temp, opts, &rda, p)) Reply(5, NULL);
    else
    {
        if (opts[0])
        {
            if (c.auth.p)
                FreeMem(c.auth.p, c.auth.s);
            
            if (key = EnBaseString((TEXT *)opts[0])) {
                
                c.auth.s = strlen((TEXT *)key) + 1;
                
                if (c.auth.p = AllocMem(c.auth.s, NULL)) {
                    strcpy(c.auth.p, key);
                    Reply(NULL, NULL);
                }
                else {
                    c.auth.p = NULL;
                    Reply(1, NULL);
                }
                
                FreeBase64Str(key);
            }
        }
        else
        {
            if (c.auth.p) {
                FreeMem(c.auth.p, c.auth.s);
                c.auth.p = NULL;
            }
            Reply(NULL, NULL);
        }
        FreeArgs(&rda);
    }
}
///

/// exe_SetDir

/* DIRECTORY   (string)
**       Directory to cd to
**
** RC
**   0   Done
**   1   Failed to cd
**   5   Failed to parse args
*/

#define SetDir_Opts "DIRECTORY"

void exe_SetDir(TEXT *p)
{
    struct RDArgs rda;
    LONG opts[1]={(LONG) "PROGDIR:"};
    BPTR lock;

    if (!ReadAVar(fcts[c.CurFct].temp, opts, &rda, p)) Reply(5, NULL);
    else
    {
        if (lock = Lock((TEXT *)opts[0], ACCESS_READ))
        {
            UnLock(CurrentDir(lock));
            Reply(NULL, NULL);
        }
        else Reply(1, NULL);
        FreeArgs(&rda);
    }
}
///

/// exe_SetEMail

/*
** EMAIL       (string)
**       If "EMAIL" if not given, no user info will be sent to the remote host
**
** RC
**   0   Done
**   1   Failed to alloc mem to store EMail
**   5   ...
*/

#define SetEMail_Opts "EMAIL"

void exe_SetEMail(TEXT *p)
{
    struct RDArgs rda;
    LONG opts[1]={NULL};
    
    if (!ReadAVar(fcts[c.CurFct].temp, opts, &rda, p)) Reply(5, NULL);
    else
    {
        if (opts[0])
        {
            if (c.email.p)
                FreeMem(c.email.p, c.email.s);

            c.email.s = strlen((TEXT *)opts[0]) + 1;

            if (c.email.p = AllocMem(c.email.s, NULL))
                Reply(NULL, NULL);
            else {
                c.email.p=NULL;
                Reply(1, NULL);
            }
        }
        else
        {
            if (c.email.p) {
                FreeMem(c.email.p, c.email.s);
                c.email.p=NULL;
            }
            Reply(NULL, NULL);
        }
        
        FreeArgs(&rda);
    }
}
///

/// exe_SetMinSpaceLeft

/*
** BYTES/N     (int)
**       Minimal space to keep - Default = 0
**
** RC
**   0   OK
**   5   ...
*/

#define SetMinSpaceLeft_Opts "BYTES/N"

void exe_SetMinSpaceLeft(TEXT *p)
{
    struct RDArgs rda;
    LONG opts[1], opts_0=0;

    opts[0] = (LONG) &opts_0;
    
    if (!ReadAVar(fcts[c.CurFct].temp, opts, &rda, p)) Reply(5, NULL);
    else
    {
        c.minspace = *(ULONG *)opts[0];
        Reply(NULL, NULL);
        FreeArgs(&rda);
    }
}
///

/// exe_SetProgressInfo

/*
** BYTES/N     (int)
**       Minimal space to keep - Default = 0
**
** RC
**   0   OK
**   5   ...
*/

#define SetProgressInfo_Opts "STRING"

void exe_SetProgressInfo(TEXT *p)
{
    struct RDArgs rda;
    LONG opts[1], opts_0=0;

    opts[0] = (LONG) &opts_0;
    
    if (!ReadAVar(fcts[c.CurFct].temp, opts, &rda, p)) Reply(5, NULL);
    else
    {
        SetProgressUser(&s, (TEXT *)opts[0]);
        Reply(NULL, NULL);
        FreeArgs(&rda);
    }
}
///

/// exe_SetTimeZone
/*
** HOURS/N       (int)
**       How many hours to ADD to obtain GMT. If not present, considered 0
** MINUTES/N     (int)
**       How many minutes to ADD to obtain GMT. If absent, considered 0
**
** RC
**   0   OK
**   1   Change is more than 1 day, old value kept
**   5   ...
*/

#define SetTimeZone_Opts "H=HOURS/N,M=MINUTES/N"

void exe_SetTimeZone(TEXT *p)
{
    struct RDArgs rda;
    LONG opts[2]={NULL, NULL};
    const LONG opt_0 = DEF_TZ_H;
    const LONG opt_1 = DEF_TZ_M;
    LONG tmins;

    opts[0] = (LONG) &opt_0;
    opts[1] = (LONG) &opt_1;
    
    if (!ReadAVar(fcts[c.CurFct].temp, opts, &rda, p)) Reply(5, NULL);
    else
    {
        tmins = *(LONG *)opts[0] * 60 + *(LONG *)opts[1];
        
        if ((tmins > 1440) || (tmins < -1440))
        {
            // Invalid..
            Reply(1, NULL);
        }
        else
        {
            c.timezone = tmins;
            Reply(NULL, NULL);
        }
        FreeArgs(&rda);
    }
}
///

/// exe_Translate

/*
** STRING/A     (string)
**      Text to translate
** TOKEN/A      (string)
**      String containing the characters to translate
** TO/A         (string)
**      String containing the chars to translate to.
**
** Note: There must be at least 1 char in TO for each char in TOKEN.
**
** RC:
**  0   Return string in GHRES
**  1   More chars in TOKEN than in TO
**  5   Failed to parse args
*/

#define Translate_Opts  "STRING/A,TOKEN/A,TO/A"

void exe_Translate(TEXT *p)
{
    struct RDArgs rda;
    LONG opts[3]={NULL, NULL, NULL};

    if (!ReadAVar(fcts[c.CurFct].temp, opts, &rda, p)) Reply(5, NULL);
    else
    {
        if (!Transl((TEXT *)opts[0], (TEXT *)opts[1], (TEXT *)opts[2])) {
            Reply(1, NULL);
        }
        else {
            Reply(NULL, (TEXT *)opts[0]);
        }
        FreeArgs(&rda);
    }
}
///

/// exe_Version

void exe_Version(TEXT *p)
{
    Reply(NULL, (TEXT *)version + 6);
}
///

/// Function Array

const struct Functions fcts[] = {
    { "GETBYTERECD",        NULL,                   exe_GetByteRecd },
    { "GETCPS",             NULL,                   exe_GetCPS },
    { "GETHEADERSTRING",    GetHeaderString_Opts,   exe_GetHeaderString },
    { "GETHTTPFILE",        GetHTTPFile_Opts,       exe_GetHTTPFile },
    { "GETSIZE",            NULL,                   exe_GetSize },
    { "GETTICKS",           NULL,                   exe_GetTicks },
    { "QUIT",               NULL,                   exe_Quit },
    { "SETAUTH",            SetAuth_Opts,           exe_SetAuth },
    { "SETDIR",             SetDir_Opts,            exe_SetDir },
    { "SETEMAIL",           SetEMail_Opts,          exe_SetEMail },
    { "SETMINSPACELEFT",    SetMinSpaceLeft_Opts,   exe_SetMinSpaceLeft },
    { "SETPROGRESSINFO",    SetProgressInfo_Opts,   exe_SetProgressInfo },
    { "SETTIMEZONE",        SetTimeZone_Opts,       exe_SetTimeZone },
    { "TRANSLATE",          Translate_Opts,         exe_Translate },
    { "VERSION",            NULL,                   exe_Version },
    { NULL,                 NULL,                   (void *)NULL } };
///

