/*
**      www-msql.c      -
**
**
** Copyright (c) 1995  Hughes Technologies Pty Ltd
**
** Permission to use, copy, and distribute for non-commercial purposes,
** is hereby granted without fee, providing that the above copyright
** notice appear in all copies and that both the copyright notice and this
** permission notice appear in supporting documentation.
**
** This software is provided "as is" without any expressed or implied warranty.
**
**
*/


#include <stdio.h>
#include <fcntl.h>
#ifdef OS2
#  include <stdlib.h>
#  include <string.h>
#  include <signal.h>
#else
#  include <string.h>
#  include <unistd.h>
#endif
#include <sys/types.h>

#include <msql.h>

#ifdef OS2
#  include <common/config.h>
#  include <common/portable.h>
#  include "w3-msql.h"
#  include "w3_yacc.h"
#  include "version.h"
#else
#  include "portable.h"
#  include "w3-msql.h"
#  include "version.h"
#  include "y_tab.h"
#endif



#define NUM_HANDLES     50

extern  char    *yytext;
extern  int     yylineno;

static  qHandle *handles[50];
static  int     handleCount;



/**********************************************************************
** Error routines
**
*/

error(msg)
        char    *msg;
{
        printf("</h1></h2></h3></h4></h5></h6>\n");
        printf("</select></ul></dl></ol></table>\n");
        printf("<h3><PRE>\n");
        printf("\n\nW3-mSQL Error!  -  %s\n\n",msg);
        printf("Error at line %d\n\n</PRE></H3>",yylineno);
        fflush(stdout);
}


badFormat()
{
        error("Bad W3-mSQL command format");
        fflush(stdout);
        exit(0);
}


yyerror(s)
        char    *s;
{
        char    errBuf[160];

        sprintf(errBuf,"%s near \"%s\"",s ,yytext?yytext:"");
        error(errBuf);
        fflush(stdout);
        exit(0);
}


msqlError()
{
        printf("</h1></h2></h3></h4></h5></h6>\n");
        printf("</select></ul></dl></ol></table>\n");
        printf("<h3><PRE>\n");
        printf("\n\nW3-mSQL Error ! - mSQL Database Error\n");
        printf("Error at line %d\n\n",yylineno);
#ifdef OS2
        printf("%s\n\n</PRE></H3>",msqlGetErrMsg(NULL));
#else
        printf("%s\n\n</PRE></H3>",msqlErrMsg);
#endif
        fflush(stdout);
        exit(0);
}




/**********************************************************************
** Query handle routines
**
*/


void storeHandle(qh, name)
        qHandle *qh;
        char    *name;
{
        int     count;

        if (handleCount == NUM_HANDLES)
        {
                error("Too many open queries!");
        }
        count = 0;
        while(count < NUM_HANDLES)
        {
                if (handles[count] == NULL)
                {
                        handles[count] = qh;
                        qh->name = (char *)strdup(name);
                        return;
                }
                count++;
        }
}


qHandle *removeHandle(name)
        char    *name;
{
        qHandle *cur;
        int     count;
        char    errBuf[80];

        count = 0;
        while(count < NUM_HANDLES)
        {
                cur = handles[count];
                if (cur)
                {
                        if (strcmp(cur->name,name) == 0)
                        {
                                free(cur->name);
                                handles[count] = NULL;
                                return(cur);
                        }
                }
                count++;
        }
        sprintf(errBuf,"Unknown query handle '%s'",name);
        error(errBuf);
        exit(1);
}




qHandle *getHandle(name)
        char    *name;
{
        qHandle *cur;
        int     count;
        char    errBuf[80];

        count = 0;
        while(count < NUM_HANDLES)
        {
                cur = handles[count];
                if (cur)
                {
                        if (strcmp(cur->name,name) == 0)
                        {
                                return(cur);
                        }
                }
                count++;
        }
        sprintf(errBuf,"Unknown query handle '%s'",name);
        error(errBuf);
        exit(1);
}



void setRowVariables(qh)
        qHandle *qh;
{
        int     count,
                index;
        char    name[10];

        count = msqlNumFields(qh->res);
        for (index = 0; index < count; index++)
        {
                sprintf(name,"$%d",index);
                if (qh->row)
                        setVariable(name,qh->row[index]);
                else
                        setVariable(name,"");
        }
}


void clearRowVariables(qh)
        qHandle *qh;
{
        int     count,
                index;
        char    name[10];

        count = msqlNumFields(qh->res);
        for (index = 0; index < count; index++)
        {
                sprintf(name,"$%d",index);
                clearVariable(name);
        }
}




int hex2dec(val)
        char    *val;
{
        int     decval,
                hexval;
        char    *cd;

        cd = val;
        *cd = tolower(*cd);
        *(cd+1) = tolower(*(cd+1));
        decval = 0;

        decval *= 16;
        if (*cd >= 'a')
                decval += *cd - 'a' + 10;
        else
                decval += *cd - '0';
        cd++;
        decval *= 16;
        if (*cd >= 'a')
                decval += *cd - 'a' + 10;
        else
                decval += *cd - '0';
        return(decval);
}



void parseArgs()
{
        char    *query,
                *cp1,
                *cp2,
                *method,
                var[30],
                val[2048];                                 /* val[160]; */
        int     c1;

        /*
        ** check for method (GET or POST)
        */
        query  = NULL;
        method = (char *)getenv("REQUEST_METHOD");

        /*
        ** method GET
        */
        if( NULL == method || 0 == strcmp(method, "GET") )
        {
                query = (char *)getenv("QUERY_STRING");
        }
        /*
        ** method POST
        */
        else if( 0 == strcmp(method, "POST") )
        {
                c1        = atoi(getenv("CONTENT_LENGTH"));
                query     = (char *)malloc(c1 + 1);
                if( NULL == query )
                        return;
                fread( query, sizeof(char), c1, stdin );
                query[c1] = '\0';
        }


        /*
        ** check results
        */
        if (!query)
                return;

        /*
        ** process query
        */
        cp1 = query;
        cp2 = var;
        bzero(var,sizeof(var));
        bzero(val,sizeof(val));
        *cp2++ = '$';
        while(*cp1)
        {
                if (*cp1 == '\\')
                {
                        cp1++;
                        *cp2++ = *cp1++;
                        continue;
                }
                if (*cp1 == '=')
                {
                        cp1++;
                        cp2 = val;
                        continue;
                }
                if (*cp1 == '&')
                {
                        setVariable(var,val);
                        bzero(var,sizeof(var));
                        bzero(val,sizeof(val));
                        cp1++;
                        cp2 = var;
                        *cp2++ = '$';
                        continue;
                }
                if (*cp1 == '+')
                {
                        *cp2++ = ' ';
                        cp1++;
                        continue;
                }
                if (*cp1 == '%')
                {
                        *cp2++ = hex2dec(cp1+1);
                        cp1 += 3;
                        continue;
                }
                *cp2++ = *cp1++;
        }
        setVariable(var,val);

        /*
        ** free allocated memory on method POST
        */
        if( NULL != method && 0 == strcmp(method, "POST") )
        {
          free( query );
        }

}



sendFooter()
{
        printf("<p><br><br><br><br>\n");
        printf("</dl></ul></ol></table>\n");
        printf("</h1></h2></h3></h4></h5></h6>\n");
        printf("<center><address>www-mSQL by ");
        printf("<a href=http://AusWeb.com.au/computer/Hughes>");
        printf("Hughes Technologies</a></address>\n\n");
}


/**********************************************************************
** mSQL / HTML routines
**
*/

int     sock;


void doConnect(host)
        char    *host;
{
#ifdef OS2
        char    *auth = NULL;
#endif
        char    *psz = NULL;
        int     tok;

        if (sock)
        {
                msqlClose(sock);
        }
       /*
        * check if there are '"'s at the beginning or end of the string
        */
        psz = host;
        if( NULL != psz && '\0' != *psz )
        {       if( NULL != (psz=strrchr(host, '"')) )
                {       *psz = '\0';
                }
                psz = ('"' == *host) ? &host[1] : host;
        }

#ifdef OS2
        /*
         * check for authentication (OS/2)
         */
        auth = (char *) getenv( "AUTH_TYPE" );
        if( NULL != auth && '\0' != *auth )
        {
                auth = (char *) getenv( "REMOTE_USER" );
        }
        else
        {
                auth = NULL;
        }
        sock = msqlUserConnect( psz, auth );
#else
        sock = msqlConnect(psz);
#endif
        if (sock < 0)
        {
                msqlError();
        }
        free(host);
}


void doClose()
{
        int     tok;

        if (sock)
        {
                msqlClose(sock);
        }
        sock = 0;
}


void doDatabase(db)
        char    *db;
{
        if (!sock)
        {
                error("Not connected to mSQL");
                exit(0);
        }

        if (msqlSelectDB(sock,db) < 0)
        {
                msqlError();
        }
        free(db);
}


void doQuery(query, handle)
        char    *query,
                *handle;
{
        char    *cp,
                buf[160];
        qHandle *qh;


        if (!sock)
        {
                error("Not connected to mSQL");
                exit(0);
        }

        cp = query + strlen(query) - 1;
        *cp = 0;
        if (msqlQuery(sock,(char *)substVariables(query+1)) < 0)
        {
                msqlError();
        }
        qh = (qHandle *)malloc(sizeof(qHandle));
        bzero(qh,sizeof(qHandle));
        qh->res = msqlStoreResult();
        if (qh->res)
        {
                qh->row = msqlFetchRow(qh->res);
                sprintf(buf,"%d",msqlNumRows(qh->res));
                setVariable("$NUM_ROWS",buf);
                sprintf(buf,"%d",msqlNumFields(qh->res));
                setVariable("$NUM_FIELDS",buf);
        }
        storeHandle(qh,handle);
        free(handle);
        free(query);
}


void doFree(handle)
        char    *handle;
{
        qHandle *qh;

        qh = removeHandle(handle);
        if(qh->res)
                msqlFreeResult(qh->res);
        free(handle);
}


void doField(format)
        char    *format;
{
        char    *cp;

        cp = format + strlen(format) - 1;
        *cp = 0;
        printf("%s",substVariables(format + 1));
        free(format);
}


void doFetch(handle)
        char    *handle;
{
        qHandle *qh;

        qh = getHandle(handle);
        qh->row = msqlFetchRow(qh->res);
        free(handle);
}



void doSeek(handle, pos)
        char    *handle,
                *pos;
{
        qHandle *qh;
        int     offset;

        qh = getHandle(handle);
        offset = atoi(pos);
        msqlDataSeek(qh->res,offset);
        qh->row = msqlFetchRow(qh->res);
        free(handle);
        free(pos);
}



void doTranslate(var, char1, char2)
        char    *var,
                *char1,
                *char2;
{
        char    *val,
                *cp,
                *c1,
                *c2;

        val = getVariable(var);
        cp = val;
        c1 = char1 + 1;
        c2 = char2 + 1;
        while(*cp)
        {
                if (*cp == *c1)
                        *cp=*c2;
                cp++;
        }
}




void doPrintRows(handle, format)
        char    *handle,
                *format;
{
        char    *cp;
        m_row   row;
        qHandle *qh;

        cp = format + strlen(format) - 1;
        *cp = 0;
        qh = getHandle(handle);
        row = qh->row;
        while(row)
        {
                setRowVariables(qh);
                printf("%s",substVariables(format+1));
                row = qh->row = msqlFetchRow(qh->res);
        }

        free(handle);
        free(format);
        clearRowVariables(qh);
}




main(argc,argv)
        int     argc;
        char    *argv[];
{
        int     fd,
                tok;
        char    *filename = NULL;
        extern  int yydebug;
#ifdef OS2
        void    *oldAbrtSignal  = NULL;
        void    *oldBreakSignal = NULL;
        void    *oldFpeSignal   = NULL;
        void    *oldIntSignal   = NULL;
        void    *oldSegvSignal  = NULL;
        void    *oldTermSignal  = NULL;
#endif

#ifdef DEBUG
        yydebug++;
#endif

        printf("Content-type: text/html\n\n");
        printf("<! HTML W3-mSQL %s >\n", W3MSQL_VERSION);
        sock = 0;

        filename = (char *)getenv("PATH_TRANSLATED");
        if (!filename)
        {
                error("Input file name missing!");
                exit(1);
        }

#ifdef OS2
        fd = open(filename,O_RDONLY | O_BINARY);
#else
        fd = open(filename,O_RDONLY);
#endif
        if (fd < 0)
        {
                error("Can't open input file");
                perror("open");
                printf("\n\n");
                exit(1);
        }

#ifdef OS2
        /*
         * ignore nearly all signals
         */
        oldAbrtSignal  = (void *) signal( SIGABRT,  SIG_IGN );
        oldBreakSignal = (void *) signal( SIGBREAK, SIG_IGN );
        oldFpeSignal   = (void *) signal( SIGFPE,   SIG_IGN );
        oldIntSignal   = (void *) signal( SIGINT,   SIG_IGN );
        oldSegvSignal  = (void *) signal( SIGSEGV,  SIG_IGN );
        oldTermSignal  = (void *) signal( SIGTERM,  SIG_IGN );
#endif

        parseArgs();
        initScanner(fd);

        yyparse();

#ifdef OS2
        /*
         * restore signals
         */
        signal( SIGABRT,  (void (*)()) oldAbrtSignal  );
        signal( SIGBREAK, (void (*)()) oldBreakSignal );
        signal( SIGFPE,   (void (*)()) oldFpeSignal   );
        signal( SIGINT,   (void (*)()) oldIntSignal   );
        signal( SIGSEGV,  (void (*)()) oldSegvSignal  );
        signal( SIGTERM,  (void (*)()) oldTermSignal  );
#endif

        exit(0);
}
