/*
_____       _    _    Corso   Italia,  178
(_|__   .  (_   |_|_  56125           Pisa
(_|_) |)|(()_)()| |   tel.  +39  050 46380
  |   |               picosoft@picosoft.it

 Copyright (C) Picosoft s.r.l. 1995-2002

 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
static char rcsid[] = "$Id: connect.cpp 5.4 2001/04/19 09:39:56 picoSoft Exp Administrator $";
# include "database.h"
# include "sqlpars.h"
# define MAXDBDIR 128
# include "trace.h"
# include "sqltype.h"
# include "envirini.h"
# include "environ.h"
extern "C" {
# include <string.h>
# include <ctype.h>
# include <stdlib.h>
# ifdef MSDOS
# include <dos.h>
extern HINSTANCE ghInstance;   // DLL handle.
# endif

static char Password[9 + 1];
static char User[9 + 1]; 

//   CONNECT.C
//
//   SQLC connection functions.
 
# include "picoisam.h"
PBool PTransaction = PFalse;

//   Allocates an environment, connection, statement, or descriptor handles
SQLRETURN SQL_API
SQLAllocHandle (SQLSMALLINT handleType,
                SQLHANDLE inputHandle,
                SQLHANDLE * outputHandlePtr)
{
   SQLRETURN Return;

   switch (handleType) {
   case SQL_HANDLE_ENV:
      Return = SQLAllocEnv (outputHandlePtr);
      break;
   case SQL_HANDLE_DBC:
      Return = SQLAllocConnect (inputHandle, outputHandlePtr);
      break;
   case SQL_HANDLE_STMT:
      Return = SQLAllocStmt (inputHandle, outputHandlePtr);
      break;
   case SQL_HANDLE_DESC:
   default:
      Return = SQL_ERROR;
      break;
   }
   return Return;
}

SQLRETURN SQL_API
SQLFreeHandle (SQLSMALLINT handleType,
	            SQLHANDLE handle)
{
   SQLRETURN Return;

   switch (handleType) {
   case SQL_HANDLE_ENV:
      Return = SQLFreeEnv (handle);
      break;
   case SQL_HANDLE_DBC:
      Return = SQLFreeConnect (handle);
      break;
   case SQL_HANDLE_STMT:
      Return = SQLFreeStmt (handle, SQL_DROP);
      break;
   case SQL_HANDLE_DESC:
   default:
      Return = SQL_ERROR;
      break;
   }
   return Return;
}

// Sets attributes that govern aspects of environments

SQLRETURN SQL_API
SQLSetEnvAttr(SQLHENV environmentHandle,
              SQLINTEGER attribute,
              SQLPOINTER valuePtr,
              SQLINTEGER stringLength)
{
   SQLRETURN Return = SQL_SUCCESS;
   Environment *env = (Environment *)environmentHandle;

   if (env == 0 || !env->IsA(Environment::Class))
      Return = SQL_INVALID_HANDLE;
   else {
      switch (attribute) {
      case SQL_ATTR_ODBC_VERSION:
         Return = env->setVersion ((long) valuePtr);
         break;
      case SQL_ATTR_OUTPUT_NTS:
         if ((long) valuePtr != SQL_TRUE) {
            PrintError (env, 0, 0, E_GENERAL_ERROR_C00, "");
            Return = SQL_ERROR;
         }
         break;
      case SQL_ATTR_CP_MATCH:
      case SQL_ATTR_CONNECTION_POOLING:
      default:
         PrintError (env, 0, 0, E_GENERAL_ERROR_C00, "");
         Return = SQL_ERROR;
         break;
      }
   }
   return Return;
}


// Returns the current setting of an environment attribute

SQLRETURN SQL_API
SQLGetEnvAttr(SQLHENV environmentHandle,
              SQLINTEGER attribute,
              SQLPOINTER valuePtr,
              SQLINTEGER bufferLength,
              SQLINTEGER *stringLengthPtr)
{
   SQLRETURN Return = SQL_SUCCESS;
   Environment *env = (Environment *)environmentHandle;

   if (env == 0 || !env->IsA(Environment::Class))
      Return = SQL_INVALID_HANDLE;
   else {
      switch (attribute) {
      case SQL_ATTR_ODBC_VERSION:
         valuePtr = (void*) env->getVersion ();
         break;
      case SQL_ATTR_OUTPUT_NTS:
         valuePtr = (void*) SQL_TRUE;
         break;
      case SQL_ATTR_CP_MATCH:
      case SQL_ATTR_CONNECTION_POOLING:
      default:
         PrintError (env, 0, 0, E_GENERAL_ERROR_C00, "");
         Return = SQL_ERROR;
         break;
      }
   }
   return Return;
}

//   Allocate an environment (ENV) block.

RETCODE SQL_API SQLAllocEnv(
   HENV FAR * phenv)
{
   Environment *env = new Environment();
   *phenv = env;
   return SQL_SUCCESS;
}

//   Allocate a DBC block.

RETCODE   SQL_API SQLAllocConnect(
   HENV   henv,
   HDBC FAR * phdbc)
{
   SQLRETURN Return = SQL_SUCCESS;
   DataBase *db;
   Environment *env = (Environment *)henv;

   if (env == 0 || !env->IsA(Environment::Class))
      Return = SQL_INVALID_HANDLE;
   else {
      db = new DataBase(*env);
      *phdbc = (HDBC) db;
   }
   return SQL_SUCCESS;
}

RETCODE SQL_API SQLConnect(
   HDBC   hdbc,
   UCHAR FAR *szDSN,
   SWORD   cbDSN,
   UCHAR FAR *szUID,
   SWORD   cbUID,
   UCHAR FAR *szAuthStr,
   SWORD   cbAuthStr)
{
   static char szDbDir[MAXDBDIR + 1];
   char *nomeDB;
   char *nomeUID;  
   char traceSet[3 + 1]; 
   RETCODE Return = SQL_SUCCESS;
   EnvirIni odbcEnv;
   if ((cbDSN < 0 && cbDSN != SQL_NTS) ||
       (cbUID < 0 && cbUID != SQL_NTS) ||
       (cbAuthStr < 0 && cbAuthStr != SQL_NTS)) {
      ((DataBase *) hdbc)->PrintError (E_GENERAL_ERROR_090, "");
      Return = SQL_ERROR;
   } else {
      if (cbDSN > 0) {
         nomeDB = new char [cbDSN + 1];
         memcpy(nomeDB, szDSN, cbDSN);
         nomeDB[cbDSN] = 0;
      } else
         nomeDB = (char *) szDSN;
      if (szUID) {
         if (cbUID < 0)
            cbUID = strlen ((char*)szUID);
         if (cbUID > 0) {
            nomeUID = new char [cbUID + 9 + 1];
            memcpy (nomeUID, "USERNAME=", 9);
            memcpy(nomeUID + 9, szUID, cbUID);
            nomeUID[cbUID + 9] = 0;
            putenv (nomeUID);
         }
      }
 
      if (cbAuthStr < 0)
         cbAuthStr = strlen ((char*)szAuthStr);
      if (cbAuthStr > 0) {
         cbAuthStr = cbAuthStr > 9 ? 9 : cbAuthStr;
      }
      if (hdbc == 0 ||
          !((PObject *) hdbc)->IsA (DataBase::Class))
         Return = SQL_INVALID_HANDLE;
      else {
         ((DataBase *) hdbc)->DelError();
         if(odbcEnv.Read((char *)nomeDB, "PLogFile", szDbDir, sizeof(szDbDir)) > 0) {
            pIslogopen (szDbDir);
            PTransaction = PTrue;
         } else if (odbcEnv.Read((char *)nomeDB, "PTransaction", szDbDir, sizeof(szDbDir)) > 0) {
            if (szDbDir[0] == 'Y')
               PTransaction = PTrue;
         }
         if(odbcEnv.Read((char *)nomeDB, "DataDirectory", (char *) szDbDir, sizeof(szDbDir)) == 0) {
            if(odbcEnv.Read("Default", "DataDirectory", szDbDir, sizeof(szDbDir)) == 0) {
               ((DataBase *) hdbc)->PrintError (E_CONN_EXCEPT_001,
                         "Data source not found and no default driver specified");
               Return = SQL_ERROR;
            }
         }
         if (Return != SQL_ERROR) {
            char user[9 + 1];
            char passwd[9 + 1];
            if (odbcEnv.Read((char *)nomeDB, "User",  user, 9) == 0)
               user[0] = '\0';
            else
               user[9] = '\0';
            if (odbcEnv.Read((char *)nomeDB,"Password",passwd,9)==0)
               passwd[0] = '\0';
            else
               passwd[9] = '\0';
            if ((user[0] != 0 &&
                 (cbUID != strlen(user) ||
                  memcmp(user, szUID, cbUID)) != 0) ||
                (passwd[0]!=0 &&
                 (cbAuthStr!=strlen(passwd) ||
                  memcmp(passwd,szAuthStr,cbAuthStr)) != 0)) {
               ((DataBase *) hdbc)->PrintError (E_CONN_EXCEPT_001,
                         "Invalid user/password");
               Return = SQL_ERROR;
            }
         }

         if (Return != SQL_ERROR) {
            ((DataBase *) hdbc)->setNome(nomeDB);
            Return = ((DataBase *) hdbc)->Connect (szDbDir);
         }

      }
      if (odbcEnv.Read((char *)nomeDB, "PicoOdbcTrace", traceSet, sizeof(traceSet)) > 0)
         if (traceSet[0] == 'Y')
            Trace.isSet = 1;
      if (nomeDB != (char *) szDSN)
         delete nomeDB;
   }   
         
   if (Trace.isSet)
# ifdef MSDOS
      Trace.Open("\\PICOODBC.LO0");
# else
      Trace.Open("/tmp/PICOODBC.LO0");
# endif // MSDOS
   if (Trace.isSet)
      Trace.Write ("SQLConnect(0x%lx,'%s',%d,'%s',%d,'%s',%d)=%d\n",
                    hdbc, nomeDB, cbDSN, szUID, cbUID,
                               szAuthStr, cbAuthStr, Return);
   return Return; 
}

# ifdef MSDOS

PBool FAR PASCAL FDriverConnectProc(
   HWND   hdlg,
   UINT   wMsg,
   WPARAM   wParam,
   LPARAM   lParam)
{
   switch (wMsg) {
   case WM_INITDIALOG:
      return PTrue;

   case WM_COMMAND:
      switch (wParam) {
      case IDOK:
         GetDlgItemText(hdlg, 1000, User, sizeof(User));
         GetDlgItemText(hdlg, 1001, Password, sizeof(Password));
         EndDialog(hdlg, PTrue);
         return PTrue;

      case IDCANCEL:
         EndDialog(hdlg, PFalse);
         return PTrue;
      }
   }
   return PFalse;
}

//   This function as its "normal" behavior is supposed to bring up a
//   dialog box if it isn't given enough information via "szConnStrIn".  If
//   it is given enough information, it's supposed to use "szConnStrIn" to
//   establish a database connection.  In either case, it returns a
//   string to the user that is the string that was eventually used to
//   establish the connection.

RETCODE   SQL_API SQLDriverConnect(
   HDBC   hdbc,
   HWND   hwnd,
   UCHAR FAR *szConnStrIn,
   SWORD   cbConnStrIn,
   UCHAR FAR *szConnStrOut,
   SWORD   cbConnStrOutMax,
   SWORD FAR *pcbConnStrOut,
   UWORD fDriverCompletion)
{
   RETCODE Return = SQL_SUCCESS;
   PString nomeDB;
   PString nomeUID;
   PString nomePWD;
   PBool   fPrompt = PFalse;
   char *puntdsn = (char *)0;
   char *semicolon = (char *)0;
   int iRet;
   char ProfString[10]; 
   char ProfStringUPPER[10];
   PBool PasswordRequest = PFalse;
   EnvirIni odbcEnv;

   if ((cbConnStrIn < 0 && cbConnStrIn != SQL_NTS) ||
        cbConnStrOutMax < 0) {
      ((DataBase *) hdbc)->PrintError (E_GENERAL_ERROR_090, "");
      Return = SQL_ERROR;
   } else {
      if ( ! (fDriverCompletion == SQL_DRIVER_PROMPT ||
              fDriverCompletion == SQL_DRIVER_COMPLETE ||
              fDriverCompletion == SQL_DRIVER_COMPLETE_REQUIRED ||
              fDriverCompletion == SQL_DRIVER_NOPROMPT) ) {
         ((DataBase *) hdbc)->PrintError (E_GENERAL_ERROR_110, "");
         Return = SQL_ERROR;
      } else {
         if ((puntdsn = strstr((char *) szConnStrIn, "DSN=")) != (char *)0) {
            if ((semicolon = strchr(puntdsn, ';')) != 0) {
               *semicolon = 0;
               nomeDB = puntdsn + strlen("DSN=");
               *semicolon = ';';
            } else
               nomeDB = puntdsn + strlen("DSN=");
            if (odbcEnv.Read(nomeDB.gets(), "PasswordRequest", (char *) ProfString, sizeof(ProfString)) != 0) {
               strcpy(ProfStringUPPER, ProfString);
               puntdsn = ProfStringUPPER;
               while (*puntdsn)
                  *puntdsn++ = toupper(*puntdsn);
               if (!strcmp (ProfStringUPPER, "YES"))
                  PasswordRequest = PTrue; 
               else if (strcmp (ProfStringUPPER, "NO")) 
                  nomePWD = ProfString; 
            }
         } else if ((puntdsn = strstr((char *) szConnStrIn, "DRIVER=")) != (char *)0) {
            ((DataBase *) hdbc)->PrintError (E_INTERNAL_ERROR_001, "");
            return Return = SQL_ERROR;
         } else {
            ((DataBase *) hdbc)->PrintError (E_INTERNAL_ERROR_007,  "");
            return Return = SQL_ERROR;
         }
         if ((puntdsn = strstr((char *) szConnStrIn, "UID=")) != (char *)0) {
            if ((semicolon = strchr(puntdsn, ';')) != 0) {
               *semicolon = 0;
               nomeUID = puntdsn + strlen("UID=");
               *semicolon = ';';
            } else
               nomeUID = puntdsn + strlen("UID=");
         } 
         if ((puntdsn = strstr((char *) szConnStrIn, "PWD=")) != (char *)0) {
            if ((semicolon = strchr(puntdsn, ';')) != 0) {
               *semicolon = 0;
               nomePWD = puntdsn + strlen("PWD=");
               *semicolon = ';';
            } else
               nomePWD = puntdsn + strlen("PWD=");
         } 

         if ((szConnStrIn == NULL) || (!cbConnStrIn) ||
             ((cbConnStrIn == SQL_NTS) && (!szConnStrIn[0])))
            fPrompt = PTrue;
         else {
        //  Check connection string for completeness
            if (fDriverCompletion == SQL_DRIVER_PROMPT)
              fPrompt = PTrue;
         }
         if (fPrompt) {
        //   It is not necessary to call "MakeProcInstance" if you
        //   generate a dialog box from a DLL.
        //
           iRet = DialogBox(ghInstance, "EDRIVERCONNECT", hwnd, (DLGPROC) FDriverConnectProc);
           if ((!iRet) || (iRet == -1))
              return SQL_NO_DATA_FOUND;
           else {
              nomeUID = User;
              nomePWD = Password;
           }   
         }
         Return = SQLConnect(hdbc,
                            (UCHAR *) nomeDB.gets(), (SWORD) nomeDB.size(),
                            (UCHAR *) nomeUID.gets(), (SWORD) nomeUID.size(),
                            (UCHAR *) nomePWD.gets(), (SWORD) nomePWD.size());
         if (szConnStrOut != (UCHAR FAR *) 0) {
            sprintf ((char *) szConnStrOut, "DSN=%s;", nomeDB.gets());
            puntdsn = (char *) (szConnStrOut + lstrlen((char *) szConnStrOut));
            if (nomeUID.size() > 0) {
               sprintf ((char *) puntdsn, "UID=%s;", nomeUID.gets());
               puntdsn = (char *) (szConnStrOut + lstrlen((char *) szConnStrOut));
            }
            if (nomePWD.size() > 0)
               sprintf ((char *) puntdsn, "PWD=%s;", nomePWD.gets());
         }
         if (pcbConnStrOut != (SWORD FAR *) 0)
            *pcbConnStrOut = lstrlen((char *) szConnStrOut);
      }
   }
   if (Trace.isSet)
      Trace.Write ("SQLDriverConnect(0x%lx,0x%x,'%s',%d,'%s',%d,...,%d)=%d)\n",
                       hdbc,hwnd,szConnStrIn,cbConnStrIn,
                       szConnStrOut,cbConnStrOutMax,
                  fDriverCompletion,Return);
    return Return;
}
# endif // MSDOS


RETCODE SQL_API SQLDisconnect(
   HDBC   hdbc)
{
   RETCODE Return = SQL_SUCCESS;

   if (hdbc == 0 ||
       !((PObject *) hdbc)->IsA (DataBase::Class))
      Return = SQL_INVALID_HANDLE;
   else {
      ((DataBase *) hdbc)->Clear();
   }
   if (Trace.isSet) {
      Trace.Write ("SQLDisconnect(0x%lx)=%d\n",hdbc, Return);
      Trace.Close();
   }
   return Return;
}

RETCODE   SQL_API SQLFreeConnect(
   HDBC   hdbc)
{
   RETCODE Return = SQL_SUCCESS;

   if (hdbc == 0 ||
       !((PObject *) hdbc)->IsA (DataBase::Class))
      Return = SQL_INVALID_HANDLE;
   else
      delete (DataBase *) hdbc;

   return Return;
}
 

RETCODE SQL_API SQLFreeEnv(
   HENV   henv)
{ 
   RETCODE Return = SQL_SUCCESS;

   if (henv == 0 ||
       !((PObject *) henv)->IsA (Environment::Class))
      Return = SQL_INVALID_HANDLE;
   else
      delete (Environment *) henv;

   return Return;
}

/*
RETCODE   SQL_API SQLBrowseConnect(
   HDBC   hdbc,
   UCHAR FAR *szConnStrIn,
   SWORD   cbConnStrIn,
   UCHAR FAR *szConnStrOut,
   SWORD   cbConnStrOutMax,
   SWORD FAR *pcbConnStrOut)
{   
   if (Trace.isSet)
      Trace.Write ("SQLBrowseConnect\n"); 
    return SQL_SUCCESS;
}
*/
};
