439 lines
9.8 KiB
C
439 lines
9.8 KiB
C
/*-------
|
|
Module: drvconn.c
|
|
*
|
|
* Description: This module contains only routines related to
|
|
* implementing SQLDriverConnect.
|
|
*
|
|
* Classes: n/a
|
|
*
|
|
* API functions: SQLDriverConnect
|
|
*
|
|
* Comments: See "notice.txt" for copyright and license information.
|
|
*-------
|
|
*/
|
|
|
|
#include "psqlodbc.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "connection.h"
|
|
|
|
#ifndef WIN32
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#define NEAR
|
|
#else
|
|
#include <winsock.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
|
|
#ifdef WIN32
|
|
#include <windowsx.h>
|
|
#include "resource.h"
|
|
#endif
|
|
#include "pgapifunc.h"
|
|
|
|
#ifndef TRUE
|
|
#define TRUE (BOOL)1
|
|
#endif
|
|
#ifndef FALSE
|
|
#define FALSE (BOOL)0
|
|
#endif
|
|
|
|
#include "dlg_specific.h"
|
|
|
|
/* prototypes */
|
|
void dconn_get_connect_attributes(const UCHAR FAR *connect_string, ConnInfo *ci);
|
|
static void dconn_get_common_attributes(const UCHAR FAR *connect_string, ConnInfo *ci);
|
|
|
|
#ifdef WIN32
|
|
BOOL FAR PASCAL dconn_FDriverConnectProc(HWND hdlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
|
|
RETCODE dconn_DoDialog(HWND hwnd, ConnInfo *ci);
|
|
|
|
extern HINSTANCE NEAR s_hModule;/* Saved module handle. */
|
|
|
|
#endif
|
|
|
|
|
|
RETCODE SQL_API
|
|
PGAPI_DriverConnect(
|
|
HDBC hdbc,
|
|
HWND hwnd,
|
|
UCHAR FAR *szConnStrIn,
|
|
SWORD cbConnStrIn,
|
|
UCHAR FAR *szConnStrOut,
|
|
SWORD cbConnStrOutMax,
|
|
SWORD FAR *pcbConnStrOut,
|
|
UWORD fDriverCompletion)
|
|
{
|
|
static char *func = "PGAPI_DriverConnect";
|
|
ConnectionClass *conn = (ConnectionClass *) hdbc;
|
|
ConnInfo *ci;
|
|
|
|
#ifdef WIN32
|
|
RETCODE dialog_result;
|
|
|
|
#endif
|
|
RETCODE result;
|
|
char connStrIn[MAX_CONNECT_STRING];
|
|
char connStrOut[MAX_CONNECT_STRING];
|
|
int retval;
|
|
char password_required = FALSE;
|
|
int len = 0;
|
|
SWORD lenStrout;
|
|
|
|
|
|
mylog("%s: entering...\n", func);
|
|
|
|
if (!conn)
|
|
{
|
|
CC_log_error(func, "", NULL);
|
|
return SQL_INVALID_HANDLE;
|
|
}
|
|
|
|
make_string(szConnStrIn, cbConnStrIn, connStrIn);
|
|
|
|
mylog("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, connStrIn);
|
|
qlog("conn=%u, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, connStrIn, fDriverCompletion);
|
|
|
|
ci = &(conn->connInfo);
|
|
|
|
/* Parse the connect string and fill in conninfo for this hdbc. */
|
|
dconn_get_connect_attributes(connStrIn, ci);
|
|
|
|
/*
|
|
* If the ConnInfo in the hdbc is missing anything, this function will
|
|
* fill them in from the registry (assuming of course there is a DSN
|
|
* given -- if not, it does nothing!)
|
|
*/
|
|
getDSNinfo(ci, CONN_DONT_OVERWRITE);
|
|
dconn_get_common_attributes(connStrIn, ci);
|
|
logs_on_off(1, ci->drivers.debug, ci->drivers.commlog);
|
|
|
|
/* Fill in any default parameters if they are not there. */
|
|
getDSNdefaults(ci);
|
|
/* initialize pg_version */
|
|
CC_initialize_pg_version(conn);
|
|
|
|
#ifdef WIN32
|
|
dialog:
|
|
#endif
|
|
ci->focus_password = password_required;
|
|
|
|
switch (fDriverCompletion)
|
|
{
|
|
#ifdef WIN32
|
|
case SQL_DRIVER_PROMPT:
|
|
dialog_result = dconn_DoDialog(hwnd, ci);
|
|
if (dialog_result != SQL_SUCCESS)
|
|
return dialog_result;
|
|
break;
|
|
|
|
case SQL_DRIVER_COMPLETE_REQUIRED:
|
|
|
|
/* Fall through */
|
|
|
|
case SQL_DRIVER_COMPLETE:
|
|
|
|
/* Password is not a required parameter. */
|
|
if (ci->username[0] == '\0' ||
|
|
ci->server[0] == '\0' ||
|
|
ci->database[0] == '\0' ||
|
|
ci->port[0] == '\0' ||
|
|
password_required)
|
|
{
|
|
dialog_result = dconn_DoDialog(hwnd, ci);
|
|
if (dialog_result != SQL_SUCCESS)
|
|
return dialog_result;
|
|
}
|
|
break;
|
|
#else
|
|
case SQL_DRIVER_PROMPT:
|
|
case SQL_DRIVER_COMPLETE:
|
|
case SQL_DRIVER_COMPLETE_REQUIRED:
|
|
#endif
|
|
case SQL_DRIVER_NOPROMPT:
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Password is not a required parameter unless authentication asks for
|
|
* it. For now, I think it's better to just let the application ask
|
|
* over and over until a password is entered (the user can always hit
|
|
* Cancel to get out)
|
|
*/
|
|
if (ci->username[0] == '\0' ||
|
|
ci->server[0] == '\0' ||
|
|
ci->database[0] == '\0' ||
|
|
ci->port[0] == '\0')
|
|
{
|
|
/* (password_required && ci->password[0] == '\0')) */
|
|
|
|
return SQL_NO_DATA_FOUND;
|
|
}
|
|
|
|
/* do the actual connect */
|
|
retval = CC_connect(conn, password_required);
|
|
if (retval < 0)
|
|
{ /* need a password */
|
|
if (fDriverCompletion == SQL_DRIVER_NOPROMPT)
|
|
{
|
|
CC_log_error(func, "Need password but Driver_NoPrompt", conn);
|
|
return SQL_ERROR; /* need a password but not allowed to
|
|
* prompt so error */
|
|
}
|
|
else
|
|
{
|
|
#ifdef WIN32
|
|
password_required = TRUE;
|
|
goto dialog;
|
|
#else
|
|
return SQL_ERROR; /* until a better solution is found. */
|
|
#endif
|
|
}
|
|
}
|
|
else if (retval == 0)
|
|
{
|
|
/* error msg filled in above */
|
|
CC_log_error(func, "Error from CC_Connect", conn);
|
|
return SQL_ERROR;
|
|
}
|
|
|
|
/*
|
|
* Create the Output Connection String
|
|
*/
|
|
result = SQL_SUCCESS;
|
|
|
|
lenStrout = cbConnStrOutMax;
|
|
if (conn->ms_jet && lenStrout > 255)
|
|
lenStrout = 255;
|
|
makeConnectString(connStrOut, ci, lenStrout);
|
|
len = strlen(connStrOut);
|
|
|
|
if (szConnStrOut)
|
|
{
|
|
|
|
/*
|
|
* Return the completed string to the caller. The correct method
|
|
* is to only construct the connect string if a dialog was put up,
|
|
* otherwise, it should just copy the connection input string to
|
|
* the output. However, it seems ok to just always construct an
|
|
* output string. There are possible bad side effects on working
|
|
* applications (Access) by implementing the correct behavior,
|
|
* anyway.
|
|
*/
|
|
strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax);
|
|
|
|
if (len >= cbConnStrOutMax)
|
|
{
|
|
int clen;
|
|
for (clen = strlen(szConnStrOut) - 1; clen >= 0 && szConnStrOut[clen] != ';'; clen--)
|
|
szConnStrOut[clen] = '\0';
|
|
result = SQL_SUCCESS_WITH_INFO;
|
|
conn->errornumber = CONN_TRUNCATED;
|
|
conn->errormsg = "The buffer was too small for the ConnStrOut.";
|
|
}
|
|
}
|
|
|
|
if (pcbConnStrOut)
|
|
*pcbConnStrOut = len;
|
|
|
|
mylog("szConnStrOut = '%s' len=%d,%d\n", szConnStrOut, len, cbConnStrOutMax);
|
|
qlog("conn=%u, PGAPI_DriverConnect(out)='%s'\n", conn, szConnStrOut);
|
|
|
|
|
|
mylog("PGAPI_DRiverConnect: returning %d\n", result);
|
|
return result;
|
|
}
|
|
|
|
|
|
#ifdef WIN32
|
|
RETCODE
|
|
dconn_DoDialog(HWND hwnd, ConnInfo *ci)
|
|
{
|
|
int dialog_result;
|
|
|
|
mylog("dconn_DoDialog: ci = %u\n", ci);
|
|
|
|
if (hwnd)
|
|
{
|
|
dialog_result = DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_CONFIG),
|
|
hwnd, dconn_FDriverConnectProc, (LPARAM) ci);
|
|
if (!dialog_result || (dialog_result == -1))
|
|
return SQL_NO_DATA_FOUND;
|
|
else
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
return SQL_ERROR;
|
|
}
|
|
|
|
|
|
BOOL FAR PASCAL
|
|
dconn_FDriverConnectProc(
|
|
HWND hdlg,
|
|
UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
ConnInfo *ci;
|
|
|
|
switch (wMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
ci = (ConnInfo *) lParam;
|
|
|
|
/* Change the caption for the setup dialog */
|
|
SetWindowText(hdlg, "PostgreSQL Connection");
|
|
|
|
SetWindowText(GetDlgItem(hdlg, IDC_DATASOURCE), "Connection");
|
|
|
|
/* Hide the DSN and description fields */
|
|
ShowWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hdlg, IDC_DSNAME), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hdlg, IDC_DESCTEXT), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hdlg, IDC_DESC), SW_HIDE);
|
|
|
|
SetWindowLong(hdlg, DWL_USER, lParam); /* Save the ConnInfo for
|
|
* the "OK" */
|
|
SetDlgStuff(hdlg, ci);
|
|
|
|
if (ci->database[0] == '\0')
|
|
; /* default focus */
|
|
else if (ci->server[0] == '\0')
|
|
SetFocus(GetDlgItem(hdlg, IDC_SERVER));
|
|
else if (ci->port[0] == '\0')
|
|
SetFocus(GetDlgItem(hdlg, IDC_PORT));
|
|
else if (ci->username[0] == '\0')
|
|
SetFocus(GetDlgItem(hdlg, IDC_USER));
|
|
else if (ci->focus_password)
|
|
SetFocus(GetDlgItem(hdlg, IDC_PASSWORD));
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
case IDOK:
|
|
ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER);
|
|
|
|
GetDlgStuff(hdlg, ci);
|
|
|
|
case IDCANCEL:
|
|
EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
|
|
return TRUE;
|
|
|
|
case IDC_DRIVER:
|
|
ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER);
|
|
DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DRV),
|
|
hdlg, driver_optionsProc, (LPARAM) ci);
|
|
break;
|
|
|
|
case IDC_DATASOURCE:
|
|
ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER);
|
|
DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DS),
|
|
hdlg, ds_optionsProc, (LPARAM) ci);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#endif /* WIN32 */
|
|
|
|
|
|
void
|
|
dconn_get_connect_attributes(const UCHAR FAR *connect_string, ConnInfo *ci)
|
|
{
|
|
char *our_connect_string;
|
|
char *pair,
|
|
*attribute,
|
|
*value,
|
|
*equals;
|
|
char *strtok_arg;
|
|
|
|
memset(ci, 0, sizeof(ConnInfo));
|
|
#ifdef DRIVER_CURSOR_IMPLEMENT
|
|
ci->updatable_cursors = 1;
|
|
#endif /* DRIVER_CURSOR_IMPLEMENT */
|
|
|
|
our_connect_string = strdup(connect_string);
|
|
strtok_arg = our_connect_string;
|
|
|
|
mylog("our_connect_string = '%s'\n", our_connect_string);
|
|
|
|
while (1)
|
|
{
|
|
pair = strtok(strtok_arg, ";");
|
|
if (strtok_arg)
|
|
strtok_arg = 0;
|
|
if (!pair)
|
|
break;
|
|
|
|
equals = strchr(pair, '=');
|
|
if (!equals)
|
|
continue;
|
|
|
|
*equals = '\0';
|
|
attribute = pair; /* ex. DSN */
|
|
value = equals + 1; /* ex. 'CEO co1' */
|
|
|
|
mylog("attribute = '%s', value = '%s'\n", attribute, value);
|
|
|
|
if (!attribute || !value)
|
|
continue;
|
|
|
|
/* Copy the appropriate value to the conninfo */
|
|
copyAttributes(ci, attribute, value);
|
|
|
|
}
|
|
|
|
free(our_connect_string);
|
|
}
|
|
|
|
static void
|
|
dconn_get_common_attributes(const UCHAR FAR *connect_string, ConnInfo *ci)
|
|
{
|
|
char *our_connect_string;
|
|
char *pair,
|
|
*attribute,
|
|
*value,
|
|
*equals;
|
|
char *strtok_arg;
|
|
|
|
our_connect_string = strdup(connect_string);
|
|
strtok_arg = our_connect_string;
|
|
|
|
mylog("our_connect_string = '%s'\n", our_connect_string);
|
|
|
|
while (1)
|
|
{
|
|
pair = strtok(strtok_arg, ";");
|
|
if (strtok_arg)
|
|
strtok_arg = 0;
|
|
if (!pair)
|
|
break;
|
|
|
|
equals = strchr(pair, '=');
|
|
if (!equals)
|
|
continue;
|
|
|
|
*equals = '\0';
|
|
attribute = pair; /* ex. DSN */
|
|
value = equals + 1; /* ex. 'CEO co1' */
|
|
|
|
mylog("attribute = '%s', value = '%s'\n", attribute, value);
|
|
|
|
if (!attribute || !value)
|
|
continue;
|
|
|
|
/* Copy the appropriate value to the conninfo */
|
|
copyCommonAttributes(ci, attribute, value);
|
|
|
|
}
|
|
|
|
free(our_connect_string);
|
|
}
|