#include "HTParse.h"
#include "HTUtils.h"
#include "HTML.h"               /* SCW */

extern int HTClientProtocol;

#define PUTC(c) (*target->isa->put_character)(target, c)
#define PUTS(s) (*target->isa->put_string)(target, s)
#define START(e) (*target->isa->start_element)(target, e, 0, 0)
#define END(e) (*target->isa->end_element)(target, e)
#define END_TARGET (*target->isa->end_document)(target)
#define FREE_TARGET (*target->isa->free)(target)
struct _HTStructured {
        CONST HTStructuredClass *       isa;
        /* ... */
};
 
struct _HTStream {
        CONST HTStreamClass *   isa;
        /* ... */
};


 
#ifndef NO_RULES
#include "HTRules.h"
#endif
 
#include <stdio.h>
 
#include "HTList.h"
#include "HText.h"      /* See bugs above */
#include "HTAlert.h"
#include <malloc.h>
#include <strings.h>
#include <string.h>
/*
#include 
*/
#define USERNAME "SCOTT" 
#define PASSWORD "TIGER" 
#define SOC_SIZE 4096
#include "HTOracle.h" 
/*
#ifndef MSDOS 
extern char *malloc(); 
#else 
extern unsigned char *malloc(); 
#endif 
*/
char *nullstring=" "; 

EXEC SQL BEGIN DECLARE SECTION; 
char *username = USERNAME; 
char *password = PASSWORD; 
VARCHAR statement[4096]; 
EXEC SQL END DECLARE SECTION; 
EXEC SQL INCLUDE sqlca;
EXEC SQL INCLUDE sqlda;
SQLDA *bind_dp;
SQLDA *select_dp;
extern SQLDA *sqlald();
extern void sqlprc();
int precision, scale;
extern void sqlnul();
short null_ok;
short *indicator;

PRIVATE char badaboum[SOC_SIZE];

#define LIEN_MAX 40
PRIVATE char *LIEN_AVANT;
PRIVATE char *LIEN_APRES;
PRIVATE char *CLEF[LIEN_MAX];
PRIVATE char *LIEN[LIEN_MAX];
PRIVATE int lien;
PRIVATE int lien_suite;

extern FILE *logfile;

/*	oracle_decode
**	-------------
**
**	Cette fonction extrait de la question les parties mises en commentaire
**	afin de les stocker dans :
**	      CLEF[]  = nom de la colonne
**	      LIEN[]  = lien associe a la colonne
*/
PRIVATE char *oracle_decode ARGS2(char *, ligne,char *, clef)
{
  char *c, *d, *e, *arg;
  char *nouveau, *retour;
  int i, log;

  arg = ligne;
  lien = -1;
  nouveau = (char *)malloc((strlen(ligne) + 1) * sizeof(char));
  if(!nouveau) {
    fprintf(stderr,"oracle_decode : allocation memoire\n");
    return (0);
  }
  LIEN_AVANT = LIEN_APRES = 0;
  c = strstr(arg,"/*");
  if(c && (c < strstr(arg,"select"))) {
    c += 2;
    if(!(d = strstr(c,"*/"))) {
      fprintf(stderr,"oracle_decode : /* non apparie\n");
      return(0);
    }
    *d++ = 0; *d++ = 0; arg = d;
    LIEN_AVANT = c;
  }
  i = strlen(arg) - 1;
  if(((*(arg+i) == '/') && (*(arg+i-1) == '*'))) {
    *(arg+i-1) = 0;
    {
      char *d, *e, *f;

      for(f=0,e=arg;d=strstr(e,"/*");f=d,e=d+2);
      if(f) {
	*f++ = 0; *f++ = 0;
	LIEN_APRES = f;
      }
    }
  }

  strcpy(nouveau,"");
  while(c = strstr(arg,"/*")) {
    lien++;
    for(d=c-1; isspace(*d) && (d!=arg); d--) *d = 0;
    *c++ = 0; *c++ = 0;
    if(*d == '"') {
      log = 1;
      *d = 0;
      if(!(d = rindex(arg,'"'))) {
	fprintf(stderr,"oracle_decode : \" non apparie\n");
	free(nouveau);
	return (0);
      }
      d++;
    } else {
      log = 0;
      for(;(d>arg) && !(isspace(*d) || *d==',');d--);
      for(e=++d;*e;e++)
	*e = toupper(*e);
    }
    CLEF[lien] = d;
    strcat(nouveau,arg);
    if(log) strcat(nouveau,"\"");
    strcat(nouveau," ");
    if(d = strstr(c,"*/")) {
      *d++ = 0; *d++ = 0;
      LIEN[lien] = c;
    } else
      return 0;
    arg = d;
  }
  strcat(nouveau,arg);
  retour = (char *)malloc(SOC_SIZE * sizeof(char));
  for(d=nouveau,i=0;i<strlen(nouveau);i++,d++) {
    if(isspace(*d)) *d = ' ';
  }
  sprintf(retour,nouveau,clef,clef,clef,clef,clef,clef,clef,clef);
  free(nouveau);
  return (retour);
}

/*	oracle_chaine
**	-------------
**
**	Enleve les blancs en debut et fin de chaine
*/
PRIVATE char *oracle_chaine ARGS1(char *, badaboum)
{
  char *c;

  for(c=(badaboum+strlen(badaboum)-1); isspace(*c) && (c!=badaboum); c--) 
	*c = 0;
  for(c=badaboum;isspace(*c);c++) ;
  return(c);
}

/*	oracle_imprime
**	--------------
**
**	Presentation dont le format se trouve contenu dans le fichier avec
**      les mot-cle suivants (devant commencer en debut de ligne) :
**
**         - ent: entete de la page = format C,8 arguments possibles (8 * clef)
**         - rep: format C par defaut a appliquer a chaque colonne
**         - que: question SQL, exemple :
**                ATTENTION PIEGE : il n'y a pas de blanc entre / et *, et * /
**                    (non-imbrication des commentaires en C)
**
**              / *<li>* /select a, b "b", c "e" / * !! %s ++ %s == %s !! * /
**              from d where %s / * tutu * /
**
**              ===> avant chaque individu impression de "<li>"
**              ===> impression de la colonne A avec le libelle "A", avec le
**                         format par defaut defini dans rep:
**              ===> impression de la colonne B avec le libelle "b", avec le
**                         format par defaut defini dans rep:
**              ===> impression de la colonne C avec le libelle "e", avec le
**                         format defini par " !! %s ++ %s == %s !!
**                         ou le 1er %s est le libelle de la colonne ("e")
**                            les autres %s pour la valeur retournee par oracle
**              ===> la question elle meme est un format C (8 * clef)
**              ===> apres chaque individu impression de " tutu "
**
**         - pie: bas de la page = format C,8 arguments possibles (8 * clef)
**
**     Remarques :
**       1) les retour-chariot et " " sont conserves dans les formats C.
**       2) La clef est encodee (HTEscape) au niveau des individus et du
**              bas de page
**          La clef est sous forme normale dans le titre et l'entete
**
*/
PRIVATE void oracle_imprime ARGS3(HTStructured *, target, SQLDA *, select_dp,
				   char *,rep)
{
  int i,j;
  char parrot[120];
  char bidiboum[SOC_SIZE];
  char *zezette;

  lien_suite = 0;
  if(LIEN_AVANT) PUTS(LIEN_AVANT);
  for (i=0; i<select_dp->F; i++) {
    indicator = (short *)select_dp->I[i];
    if(*indicator < 0) {
      if((lien_suite <= lien) && (!strcmp(CLEF[lien_suite],parrot)))
	lien_suite++;
    } else {
      j = ((int)select_dp->C[i]>119)?119:(int)select_dp->C[i];
      sprintf(parrot,"%*.*s",j,j,select_dp->S[i]);
      sprintf(bidiboum,"%*.*s ", (int)select_dp->L[i],
	      (int)select_dp->L[i],select_dp->V[i]);
      zezette = oracle_chaine(bidiboum);
      if((lien_suite <= lien) && (!strcmp(CLEF[lien_suite],parrot))) {
	sprintf(badaboum,LIEN[lien_suite],parrot,zezette,zezette);
	lien_suite++;
      } else
	sprintf(badaboum,rep?rep:"%s=%s",parrot,zezette,zezette);
      PUTS(badaboum);
    }
  }
  if(LIEN_APRES) PUTS(LIEN_APRES);
}

PRIVATE int INIT_TABLEAU;

/*	oracle_tableau
**	--------------
**
**	Presentation sous la forme :
**	  <PRE>
**	  col1  col2 ... coln
**        -------------------
**        aaa   aaa  ... aaa
**        bbb   bb   ... b
**	     ...
**	  </PRE> 
*/
PRIVATE void oracle_tableau ARGS3(HTStructured *, target, SQLDA *, select_dp,
				   char *,rep)
{
  int i;
  char buffer[SOC_SIZE]; /* @@ */

  if(INIT_TABLEAU) {
    char parrot[31];
    char *zezette;

    INIT_TABLEAU = 0;
    PUTS("<PRE>\n");
    for (i=0; i<select_dp->F; i++) {
      strncpy(parrot,select_dp->S[i],30);
      if (select_dp->T[i] == 2) {  
	while ((zezette=strchr(parrot,' ')) != 0) *zezette='\0';  
	sprintf(buffer,"%*.*s ", (int)select_dp->L[i],
		(int)select_dp->L[i], parrot);
	PUTS(buffer);
      } else {
	sprintf(buffer,"%-*.*s ",(int)select_dp->L[i],
		(int)select_dp->L[i], parrot);
	PUTS(buffer);
      }
    }

    PUTC('\n');

    for (i=0; i<select_dp->F; i++) {
      sprintf(buffer,"%*.*s ", (int)select_dp->L[i],(int)select_dp->L[i],
	      "------------------------------------------");
      PUTS(buffer);
    } 
    PUTC('\n');

  }

  for (i=0; i<select_dp->F; i++) {
    indicator = (short *)select_dp->I[i];
    sprintf(buffer,"%-*.*s ", (int)select_dp->L[i],
	    (int)select_dp->L[i],(*indicator<0)?nullstring:select_dp->V[i]);
    PUTS(buffer);
  }
  PUTC('\n');
}

/*	oracle_recherche
**	----------------
**
**	Interface a oracle.
**	Fait l'ouverture de la base
**	     pose la question et formatte les sorties
*/
PRIVATE int oracle_recherche ARGS2(RECH *, oracle, HTStructured * ,target) 
{ 
  int i,j;
  char *zozo;
  char *zezette;
  char parrot[50];
  void (*oracle_presente)();
  char *keywords;
  char buffer[SOC_SIZE]; /* @@ */

  if (!oracle->que || *oracle->que=='\0') {
/* #ts: jamais appele theoriquement */
    START(HTML_ISINDEX);
    START(HTML_TITLE);
    PUTS("Oracle Server");
    END(HTML_TITLE);
    PUTS("\n<h1>This is an Oracle Server.</h1>\nPlease enter your Request (no semicolon at the end)   ");
    END_TARGET;
    FREE_TARGET;
    return HT_LOADED;
  } 

  INIT_TABLEAU = 1;
  keywords = oracle_decode(oracle->que,oracle->cle);
/*  oracle->que = 0; */
  if(!keywords)
    return 0;

/* Titre */
  START(HTML_ISINDEX);
  START(HTML_TITLE);
  sprintf(buffer,"%s",oracle->cle);
  PUTS(buffer);
  END(HTML_TITLE);
  PUTC('\n');

/* Entete de la page */
  if(oracle->ent) {
      sprintf(buffer,oracle->ent,oracle->cle,oracle->cle,
	    oracle->cle,oracle->cle,oracle->cle,oracle->cle,
	    oracle->cle,oracle->cle); 
    PUTS(buffer);
    PUTC('\n');
  }

/* Selection de la fonction de formattage */
  oracle_presente =(oracle->typ==ORACLE_TABLEAU)?oracle_tableau:oracle_imprime;

/* Interface proprement-dit a oracle */
  EXEC SQL WHENEVER SQLERROR GOTO sqlerror;
   
  strcpy(badaboum,"ORACLE_SID=");
  strcat(badaboum,oracle->bas);
  putenv(badaboum);
  putenv("ORACLE_HOME=/usr/local/oracle");
  EXEC SQL CONNECT :username IDENTIFIED BY :password;

  bind_dp = sqlald (40, 30, 30);
  bind_dp->N = 40;
  
  select_dp = sqlald (40, 30, 30);
  select_dp->N = 40;
  
  strcpy((char *)statement.arr,keywords);
  statement.len = strlen(statement.arr);

  EXEC SQL PREPARE S FROM :statement;
  EXEC SQL DECLARE C CURSOR FOR S;
  
  EXEC SQL DESCRIBE BIND VARIABLES FOR S INTO bind_dp;
  
  if (bind_dp->F < 0) {
    PUTS("Too many bind variables for descriptor.");
    goto sqlerror;
  }

  bind_dp->N = bind_dp->F;
  
  if (bind_dp->F > 0) {
    PUTS("\nEnter value for bind variable\n");
    goto sqlerror;
  }

  EXEC SQL OPEN C USING DESCRIPTOR bind_dp;

  if ((strncmp(statement.arr, "SELECT", 6) != 0) && 
      (strncmp(statement.arr, "select", 6) != 0))
    goto end_main;

  EXEC SQL DESCRIBE SELECT LIST FOR S INTO select_dp;

  if (select_dp->F < 0) {
    sprintf(buffer, "\nToo many select-list variables for descriptor: %d",
            -(select_dp->F));
    PUTS(buffer);
    goto sqlerror;
  }
   
  select_dp->N =  select_dp->F;
  
  for (i=0; i<select_dp->F; i++) {
    sqlnul (&(select_dp->T[i]), &(select_dp->T[i]), &null_ok);

    switch (select_dp->T[i]) {
    case 1 : 
      break;
    case 2 : 
      sqlprc (&(select_dp->L[i]), &precision,&scale);
      if (precision == 0) precision = 10;
      select_dp->L[i] = precision + 2;
      if (scale < 0)
	select_dp->L[i] += -scale;
      break;
    case 8 : 
      select_dp->L[i] = 240;
      break;
    case 11 :
      select_dp->L[i] = 18;
      break;
    case 12 :
      select_dp->L[i] = 9;
      break;
    case 23 : 
      break;
    case 24 : 
      select_dp->L[i] = 240;
      break;
    }
    
    select_dp->V[i] = malloc(select_dp->L[i]);
    select_dp->I[i] = (short *)malloc(sizeof(short));
    if (select_dp->T[i] != 24)
      select_dp->T[i] = 1;

  }

  EXEC SQL WHENEVER NOT FOUND GOTO end_main;

  lien_suite = 0;

  for (j=0;j<ORACLE_MAX_REQUETE;j++) {
    EXEC SQL FETCH C USING DESCRIPTOR select_dp;
    (*oracle_presente)(target,select_dp,oracle->rep);
  }

 end_main:

/* fin: on retablit ' ' et '>' */
  for(zozo=oracle->cle; *zozo; zozo++)
    *zozo = (*zozo == ' ') ? '+': ((*zozo == '>') ? '@': *zozo);

  PUTC('\n');
  if(oracle->typ==ORACLE_TABLEAU) PUTS("\n</PRE>");

/* bas de la page */
  if(oracle->pie) {
    if(HTClientProtocol) {
      char *temp, *a;

      while(a = strchr(oracle->cle,'+')) *a = ' ';
      temp = HTEscape(oracle->cle,URL_XALPHAS);
      sprintf(buffer,oracle->pie,temp,temp,temp,temp,temp,temp,temp,temp); 
      free(temp);
    } else
      sprintf(buffer,oracle->pie,oracle->cle,oracle->cle,
	    oracle->cle,oracle->cle,oracle->cle,oracle->cle,
	    oracle->cle,oracle->cle); 
    PUTS(buffer);
    PUTC('\n');
  }


  for (i=0; i<select_dp->F; i++) {
    free (select_dp->V[i]);
    free (select_dp->I[i]);
  }

  sqlclu (bind_dp);
  sqlclu (select_dp);
  
  EXEC SQL CLOSE C;
  EXEC SQL COMMIT WORK RELEASE;
  END_TARGET;
  FREE_TARGET;
  free(keywords);
  return;
  

 sqlerror:
  sprintf(buffer,"%s<p>\n%.70s\n",keywords,sqlca.sqlerrm.sqlerrmc);
  PUTS(buffer);
  END_TARGET;
  FREE_TARGET;
  EXEC SQL WHENEVER SQLERROR CONTINUE;
  EXEC SQL ROLLBACK WORK RELEASE;
  free(keywords);
  return;

}


/* test d'acces */
extern test_from();

#define MAX_SELECT_ORACLE 1024
/*	oracle_lit_fichier
**	------------------
**
**	Lit le fichier .sql afin d'en extraire :
**	   typ :  type de presentation (tableau, liste, ...)
**	   ent :  entete de page
**	   que :  requete sql
**	   pie :  bas de page
**	
**	En profite pour verifier si l'interrogation est autorisee
*/
PRIVATE int oracle_lit_fichier ARGS3(char *, filename,char *,keywords, RECH *, oracle)
{
 
  char *c, *d, *t;
  char ligne[256];
  FILE *fdd;
  int cas;
  char *allow, *deny;
 
  oracle->typ = ORACLE_GENERAL;
  if(strstr(filename,".html")) {
    c = (char *)rindex(filename, '.');
    if(c) *c = 0;
    strcat(filename,".sql");
  }
 
/* verification d'acces */
/* #ts: pas indispensable 
  c = (char *)rindex(filename,'.');
  d = (char *)rindex(filename,'/');
  *c = *d = 0;
  if((allow = (char *)malloc((strlen(filename) + strlen("/hosts.allow") + 1)
                             * sizeof(char))) == NULL)
    return(1);
  strcpy(allow,filename);
  strcat(allow,"/hosts.allow");
  if((deny = (char *)malloc((strlen(filename) + strlen("/hosts.deny") + 1)
                             * sizeof(char))) == NULL)
    return(1);
  strcpy(deny,filename);
  strcat(deny,"/hosts.deny");
  cas = test_from((d+1),allow,deny);
  free(allow);
  free(deny);
  if(cas)
    return(2);
  *c = '.';
  *d = '/';
*/

  oracle->pie = oracle->ent = oracle->que = oracle->rep = 0;
  if((t = malloc(MAX_SELECT_ORACLE * sizeof(char))) == NULL)
    return (1);
  *t = 0;
 
/* lecture du fichier */
  if((fdd = fopen(filename,"r"))!=NULL) {
    cas = ORACLE_QUE;
    while((c=fgets(ligne,256,fdd))) {
      d = ligne;
      if(!strncmp("ent:",d,4)) {
        cas = ORACLE_ENT;
        d += 4;
      } else if(!strncmp("pie:",d,4)) {
        cas = ORACLE_PIE;
        d += 4;
      } else if(!strncmp("que:",d,4)) {
        cas = ORACLE_QUE;
        d += 4;
      } else if(!strncmp("typ:",d,4)) {
        cas = ORACLE_TYP;
        d += 4;
      } else if(!strncmp("rep:",d,4)) {
        cas = ORACLE_REP;
        d += 4;
      }
      switch (cas) {
      case ORACLE_ENT:
        if(!oracle->ent) {
          if((oracle->ent=malloc(MAX_SELECT_ORACLE * sizeof(char))) == NULL) {
            free(t);
            return (1);
          }
          *oracle->ent = 0;
        }
        strcat(oracle->ent, d);
        break;
      case ORACLE_REP:
        if(!oracle->rep) {
          if((oracle->rep= malloc(MAX_SELECT_ORACLE * sizeof(char))) == NULL) {
            free(t);
            return (1);
          }
          *oracle->rep = 0;
        }
        strcat(oracle->rep, d);
        break;
      case ORACLE_PIE:
        if(!oracle->pie) {
          if((oracle->pie= malloc(MAX_SELECT_ORACLE * sizeof(char))) == NULL) {
            free(t);
            return (1);
          }
          *oracle->pie = 0;
        }
        strcat(oracle->pie, d);
        break;
      case ORACLE_QUE:
	strcat(t, d);
        break;
      case ORACLE_TYP:
        if(strstr(d,"tableau") || strstr(d,"TABLEAU")) 
          oracle->typ = ORACLE_TABLEAU;
        else
          oracle->typ = ORACLE_GENERAL;
        break;
      }
    }
    fclose(fdd);
  } else
    strcat(t, keywords);
 
  for(c=t;isspace(*c);c++) ;
  for(cas=strlen(c)-1;(cas>1) && isspace(*(c+cas));cas--) *(c+cas) = 0;
  oracle->que = malloc((strlen(c)+1) * sizeof(char));
  strcpy(oracle->que,c);
  free(t);
  if(oracle->rep) {
    t=oracle->rep = realloc(oracle->rep,(strlen(oracle->rep)+1)*sizeof(char));
    if(isspace(*(t+strlen(t)-1))) *(t+strlen(t)-1) = 0;
  }
  if(oracle->ent) {
    t=oracle->ent = realloc(oracle->ent,(strlen(oracle->ent)+1)*sizeof(char));
    if(isspace(*(t+strlen(t)-1))) *(t+strlen(t)-1) = 0;
  }
  if(oracle->pie) {
    t=oracle->pie = realloc(oracle->pie,(strlen(oracle->pie)+1)*sizeof(char));
    if(isspace(*(t+strlen(t)-1))) *(t+strlen(t)-1) = 0;
  }
  return (0);
}

/*	HTLoadOracle
**	------------
**
**	Interface HTRetrieve ===> oracle_recherche
**	
*/
PUBLIC int HTLoadOracle ARGS4(
	CONST char *,		arg,
	HTParentAnchor *,	anAnchor,
	HTFormat,		format_out,
	HTStream*,		sink)
#define REPL_BLANC '+'
{
  char *keywords = strchr(arg,'?');
  char *filename;
  char *c, *d;
  int erreur;
  RECH oracle;

  erreur = 0;
  *keywords++ = 0;	   
  if (!*keywords) keywords = NULL;
  else {
    char *p;
    for (p=keywords; *p; p++) if (*p == REPL_BLANC) *p = ' ';
    if(HTClientProtocol) 
      HTUnEscape(keywords);
  }
  
  if(keywords) {
    {
      char * arg3;
      
      if (!(arg3 = HTTranslate(arg))) {
	if (logfile) {
	  fprintf(logfile, "** SECURITY FAIL FOR ABOVE **\n");
	  fflush(logfile);
	}
	if (TRACE) fprintf(stderr, "HTHandle: Security fail ***\n");
	return HTLoadError(sink,500,
	  "Dociment address invalid or access not authorised\n");
      }
      filename = HTParse (arg3, "", PARSE_PATH | PARSE_PUNCTUATION);
      free(arg3);
    }

/* verification d'acces */
    if(d = strstr(filename,"oracle/")) {
      for(c=keywords; (*c == '+') || isspace(*c); c++) ;
      oracle.cle = c;
      for(; *c; c++)
	if(*c == '@') *c = '>';
      if(erreur = oracle_lit_fichier(filename,oracle.cle,&oracle)) {
	if(erreur == 1) {
	  free(filename);
	  return HTLoadError(sink,500,
			     "Probleme d'allocation memoire\n");
	} else {
	  if (logfile) {
	    fprintf(logfile, "** SECURITY FAIL FOR ABOVE **\n");
	    fflush(logfile);
	  }
	  if (TRACE) fprintf(stderr, "HTHandle: Security fail ***\n");
	  free(filename);
	  return HTLoadError(sink,500,
		     "Document address invalid or access not authorised\n");
	}
      }
/* extraction du nom de la base */
      d += 7; /* #ts: !!! */
      if(c = index(d,'/'))
	*c = 0;
      oracle.bas = malloc((strlen(d) + 1) * sizeof(char));
      strcpy(oracle.bas,d);
      if(c) *c = '/';
      
      {
	HTStructured * target = HTML_new(anAnchor, format_out, sink);
	
	oracle_recherche(&oracle, target);  

	free(filename);
      }

      free(oracle.bas);
      if(oracle.que) free(oracle.que);
      if(oracle.ent) free(oracle.ent);
      if(oracle.pie) free(oracle.pie);
    } else {
      free(filename);
      return HTLoadError(sink,500,
			 "Type d'interrogation inconnu ???\n");
    }
    return HT_LOADED;
  }
  return HT_LOADED;
}



