374 lines
8.8 KiB
C
374 lines
8.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.
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "psqlodbc.h"
|
|
#include "connection.h"
|
|
|
|
#ifndef WIN32
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#define NEAR
|
|
#else
|
|
#include <winsock.h>
|
|
#include <sqlext.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
|
|
#ifndef WIN32
|
|
#define stricmp(s1,s2) strcasecmp(s1,s2)
|
|
#define strnicmp(s1,s2,n) strncasecmp(s1,s2,n)
|
|
#else
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <odbcinst.h>
|
|
#include "resource.h"
|
|
#endif
|
|
|
|
#ifndef TRUE
|
|
#define TRUE (BOOL)1
|
|
#endif
|
|
#ifndef FALSE
|
|
#define FALSE (BOOL)0
|
|
#endif
|
|
|
|
#include "dlg_specific.h"
|
|
|
|
/* prototypes */
|
|
void dconn_get_connect_attributes(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
|
|
|
|
extern GLOBAL_VALUES globals;
|
|
|
|
|
|
RETCODE SQL_API SQLDriverConnect(
|
|
HDBC hdbc,
|
|
HWND hwnd,
|
|
UCHAR FAR *szConnStrIn,
|
|
SWORD cbConnStrIn,
|
|
UCHAR FAR *szConnStrOut,
|
|
SWORD cbConnStrOutMax,
|
|
SWORD FAR *pcbConnStrOut,
|
|
UWORD fDriverCompletion)
|
|
{
|
|
static char *func = "SQLDriverConnect";
|
|
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;
|
|
|
|
|
|
mylog("%s: entering...\n", func);
|
|
|
|
if ( ! conn) {
|
|
CC_log_error(func, "", NULL);
|
|
return SQL_INVALID_HANDLE;
|
|
}
|
|
|
|
make_string(szConnStrIn, cbConnStrIn, connStrIn);
|
|
|
|
mylog("**** SQLDriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, connStrIn);
|
|
qlog("conn=%u, SQLDriverConnect( 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);
|
|
|
|
/* Fill in any default parameters if they are not there. */
|
|
getDSNdefaults(ci);
|
|
|
|
#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;
|
|
|
|
makeConnectString(connStrOut, ci);
|
|
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) {
|
|
result = SQL_SUCCESS_WITH_INFO;
|
|
conn->errornumber = CONN_TRUNCATED;
|
|
conn->errormsg = "The buffer was too small for the result.";
|
|
}
|
|
}
|
|
|
|
if(pcbConnStrOut)
|
|
*pcbConnStrOut = len;
|
|
|
|
mylog("szConnStrOut = '%s'\n", szConnStrOut);
|
|
qlog("conn=%u, SQLDriverConnect(out)='%s'\n", conn, szConnStrOut);
|
|
|
|
|
|
mylog("SQLDRiverConnect: 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:
|
|
|
|
DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DRV),
|
|
hdlg, driver_optionsProc, (LPARAM) NULL);
|
|
|
|
|
|
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(UCHAR FAR *connect_string, ConnInfo *ci)
|
|
{
|
|
char *our_connect_string;
|
|
char *pair, *attribute, *value, *equals;
|
|
char *strtok_arg;
|
|
|
|
memset(ci, 0, sizeof(ConnInfo));
|
|
|
|
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);
|
|
}
|
|
|