FIXME: toplevel Makefile: 'make ntest' doesn't run versaplexd for now.
[versaplex.git] / vxodbc / drvconn.cc
blobe5871a9992d0aa1dadb801a5d6201e642ff06ca0
1 /*
2 * Description: This module contains only routines related to
3 * implementing SQLDriverConnect.
4 */
6 #include "psqlodbc.h"
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
12 #include "connection.h"
14 #ifndef WIN32
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #define NEAR
18 #else
19 #include <winsock2.h>
20 #endif
22 #include <string.h>
24 #ifdef WIN32
25 #include <windowsx.h>
26 #include "resource.h"
27 #endif
28 #include "pgapifunc.h"
30 #include "wvdbusconn.h"
32 #include "dlg_specific.h"
33 #include "wvssl_necessities.h"
35 #define NULL_IF_NULL(a) (a ? a : "(NULL)")
37 static char *hide_password(const char *str)
39 char *outstr, *pwdp;
41 if (!str)
42 return NULL;
43 outstr = strdup(str);
44 if (pwdp = strstr(outstr, "PWD="), !pwdp)
45 pwdp = strstr(outstr, "pwd=");
46 if (pwdp)
48 char *p;
50 for (p = pwdp + 4; *p && *p != ';'; p++)
51 *p = 'x';
53 return outstr;
56 /* prototypes */
57 void dconn_get_connect_attributes(const SQLCHAR FAR * connect_string,
58 ConnInfo * ci);
59 static void dconn_get_common_attributes(const SQLCHAR FAR *
60 connect_string, ConnInfo * ci);
62 #ifdef WIN32
63 #ifdef __cplusplus
64 extern "C" {
65 #endif
66 BOOL CALLBACK dconn_FDriverConnectProc(HWND hdlg, UINT wMsg,
67 WPARAM wParam, LPARAM lParam);
68 RETCODE dconn_DoDialog(HWND hwnd, ConnInfo* ci);
69 #ifdef __cplusplus
71 #endif
73 extern HINSTANCE NEAR s_hModule; /* Saved module handle. */
74 #endif
77 RETCODE SQL_API
78 PGAPI_DriverConnect(HDBC hdbc,
79 HWND hwnd,
80 const SQLCHAR FAR * szConnStrIn,
81 SQLSMALLINT cbConnStrIn,
82 SQLCHAR FAR * szConnStrOut,
83 SQLSMALLINT cbConnStrOutMax,
84 SQLSMALLINT FAR * pcbConnStrOut,
85 SQLUSMALLINT fDriverCompletion)
87 CSTR func = "PGAPI_DriverConnect";
88 ConnectionClass *conn = (ConnectionClass *) hdbc;
89 ConnInfo *ci;
91 #ifdef WIN32
92 RETCODE dialog_result;
93 #endif
94 BOOL paramRequired, didUI = FALSE;
95 RETCODE result;
96 char *connStrIn = NULL;
97 char connStrOut[MAX_CONNECT_STRING];
98 int retval;
99 char salt[5];
100 char password_required = AUTH_REQ_OK;
101 ssize_t len = 0;
102 SQLSMALLINT lenStrout;
105 mylog("%s: entering...\n", func);
106 init_wvssl();
108 if (!conn)
110 CC_log_error(func, "", NULL);
111 return SQL_INVALID_HANDLE;
114 connStrIn = make_string(szConnStrIn, cbConnStrIn, NULL, 0);
116 #ifdef FORCE_PASSWORD_DISPLAY
117 mylog
118 ("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n",
119 fDriverCompletion, connStrIn);
120 qlog("conn=%p, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, connStrIn, fDriverCompletion);
121 #else
122 if (get_qlog() || get_mylog())
124 char *hide_str = hide_password(connStrIn);
126 mylog
127 ("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n",
128 fDriverCompletion, NULL_IF_NULL(hide_str));
129 qlog("conn=%p, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, NULL_IF_NULL(hide_str), fDriverCompletion);
130 if (hide_str)
131 free(hide_str);
133 #endif /* FORCE_PASSWORD_DISPLAY */
135 ci = &(conn->connInfo);
137 /* Parse the connect string and fill in conninfo for this hdbc. */
138 dconn_get_connect_attributes((const UCHAR *)connStrIn, ci);
140 bool dbus_provided = ci->dbus_moniker != NULL && ci->dbus_moniker[0] != '\0';
143 * If the ConnInfo in the hdbc is missing anything, this function will
144 * fill them in from the registry (assuming of course there is a DSN
145 * given -- if not, it does nothing!)
147 getDSNinfo(ci, CONN_DONT_OVERWRITE);
148 dconn_get_common_attributes((const UCHAR *)connStrIn, ci);
149 logs_on_off(1, TRUE, TRUE);
150 if (connStrIn)
152 free(connStrIn);
153 connStrIn = NULL;
156 /* Fill in any default parameters if they are not there. */
157 getDSNdefaults(ci);
158 CC_initialize_pg_version(conn);
159 memset(salt, 0, sizeof(salt));
161 ci->focus_password = password_required;
163 inolog("DriverCompletion=%d\n", fDriverCompletion);
164 switch (fDriverCompletion)
166 #ifdef WIN32
167 case SQL_DRIVER_PROMPT:
168 dialog_result = dconn_DoDialog(hwnd, ci);
169 didUI = TRUE;
170 if (dialog_result != SQL_SUCCESS)
171 return dialog_result;
172 break;
174 case SQL_DRIVER_COMPLETE_REQUIRED:
176 /* Fall through */
178 case SQL_DRIVER_COMPLETE:
180 paramRequired = password_required;
181 /* Password is not a required parameter. */
182 if (ci->database[0] == '\0')
183 paramRequired = TRUE;
184 else if (!dbus_provided && ci->port[0] == '\0')
185 paramRequired = TRUE;
186 #ifdef WIN32
187 else if (!dbus_provided && ci->server[0] == '\0')
188 paramRequired = TRUE;
189 #endif /* WIN32 */
190 if (paramRequired)
192 dialog_result = dconn_DoDialog(hwnd, ci);
193 didUI = TRUE;
194 if (dialog_result != SQL_SUCCESS)
195 return dialog_result;
197 break;
198 #else
199 case SQL_DRIVER_PROMPT:
200 case SQL_DRIVER_COMPLETE:
201 case SQL_DRIVER_COMPLETE_REQUIRED:
202 #endif
203 case SQL_DRIVER_NOPROMPT:
204 break;
208 * Password is not a required parameter unless authentication asks for
209 * it. For now, I think it's better to just let the application ask
210 * over and over until a password is entered (the user can always hit
211 * Cancel to get out)
213 paramRequired = FALSE;
214 WvString missingoptions = "Connection string lacks options: ";
215 if (ci->database[0] == '\0')
217 paramRequired = TRUE;
218 missingoptions.append("'database' ");
220 else if (!dbus_provided && ci->port[0] == '\0')
222 paramRequired = TRUE;
223 missingoptions.append("'port' ");
225 else if (!dbus_provided && ci->server[0] == '\0')
227 paramRequired = TRUE;
228 missingoptions.append("'server' ");
230 if (!dbus_provided)
232 missingoptions.append("'dbus connection' ");
234 if (paramRequired)
236 if (didUI)
237 return SQL_NO_DATA_FOUND;
238 CC_set_error(conn, CONN_OPENDB_ERROR,
239 missingoptions, func);
240 return SQL_ERROR;
243 if (!dbus_provided)
245 // If we weren't provided with a pre-made DBus moniker, use the
246 // provided server and port. If we weren't provided with those
247 // either, we'll have already returned an error above.
248 WvString moniker("dbus:tcp:host=%s,port=%s", ci->server, ci->port);
249 mylog("Moniker=%s\n", moniker.cstr());
250 if (moniker.len() < sizeof(ci->dbus_moniker))
251 strncpy(ci->dbus_moniker, moniker.cstr(), sizeof(ci->dbus_moniker));
252 else
254 CC_set_error(conn, CONN_OPENDB_ERROR,
255 "The DBus connection moniker was too long.", func);
256 return SQL_ERROR;
260 mylog("PGAPI_DriverConnect making DBus connection to %s\n",
261 ci->dbus_moniker);
262 mylog("dbus:session is '%s'\n", getenv("DBUS_SESSION_BUS_ADDRESS"));
263 conn->dbus = new WvDBusConn(ci->dbus_moniker);
265 WvDBusMsg reply = conn->dbus->send_and_wait
266 (WvDBusMsg("vx.versaplexd", "/db", "vx.db", "Test"),
267 15000);
269 if (!conn->dbus->isok())
271 CC_set_error(conn, CONN_OPENDB_ERROR, WvString(
272 "Could not open DBus connection to %s: %s (%s).",
273 ci->dbus_moniker,
274 conn->dbus->errstr(), conn->dbus->geterr()).cstr(),
275 func);
276 return SQL_ERROR;
279 if (reply.iserror())
281 WvDBusMsg::Iter i(reply);
282 WvString errstr = i.getnext();
283 CC_set_error(conn, CONN_OPENDB_ERROR, WvString(
284 "DBus connected, but test failed: %s. Is versaplexd running?",
285 errstr).cstr(),
286 func);
287 return SQL_ERROR;
291 * Create the Output Connection String
293 result = SQL_SUCCESS;
295 lenStrout = cbConnStrOutMax;
296 if (conn->ms_jet && lenStrout > 255)
297 lenStrout = 255;
298 makeConnectString(connStrOut, ci, lenStrout);
299 len = strlen(connStrOut);
301 if (szConnStrOut)
304 * Return the completed string to the caller. The correct method
305 * is to only construct the connect string if a dialog was put up,
306 * otherwise, it should just copy the connection input string to
307 * the output. However, it seems ok to just always construct an
308 * output string. There are possible bad side effects on working
309 * applications (Access) by implementing the correct behavior,
310 * anyway.
312 /*strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax); */
313 strncpy((char *)szConnStrOut, connStrOut, cbConnStrOutMax);
315 if (len >= cbConnStrOutMax)
317 int clen;
319 for (clen = cbConnStrOutMax - 1;
320 clen >= 0 && szConnStrOut[clen] != ';'; clen--)
321 szConnStrOut[clen] = '\0';
322 result = SQL_SUCCESS_WITH_INFO;
323 CC_set_error(conn, CONN_TRUNCATED,
324 "The buffer was too small for the ConnStrOut.",
325 func);
329 if (pcbConnStrOut)
330 *pcbConnStrOut = (SQLSMALLINT) len;
332 #ifdef FORCE_PASSWORD_DISPLAY
333 if (cbConnStrOutMax > 0)
335 mylog("szConnStrOut = '%s' len=%d,%d\n",
336 NULL_IF_NULL(szConnStrOut), len, cbConnStrOutMax);
337 qlog("conn=%p, PGAPI_DriverConnect(out)='%s'\n", conn,
338 NULL_IF_NULL(szConnStrOut));
340 #else
341 if (get_qlog() || get_mylog())
343 char *hide_str = NULL;
345 if (cbConnStrOutMax > 0)
346 hide_str = hide_password((const char *)szConnStrOut);
347 mylog("szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL(hide_str),
348 len, cbConnStrOutMax);
349 qlog("conn=%p, PGAPI_DriverConnect(out)='%s'\n", conn,
350 NULL_IF_NULL(hide_str));
351 if (hide_str)
352 free(hide_str);
354 #endif /* FORCE_PASSWORD_DISPLAY */
356 if (connStrIn)
357 free(connStrIn);
358 mylog("PGAPI_DriverConnect: returning %d\n", result);
359 return result;
363 #ifdef WIN32
364 RETCODE dconn_DoDialog(HWND hwnd, ConnInfo * ci)
366 LRESULT dialog_result;
368 mylog("dconn_DoDialog: ci = %p\n", ci);
370 if (hwnd)
372 dialog_result =
373 DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_CONFIG), hwnd,
374 dconn_FDriverConnectProc, (LPARAM) ci);
375 if (!dialog_result || (dialog_result == -1))
376 return SQL_NO_DATA_FOUND;
377 else
378 return SQL_SUCCESS;
381 return SQL_ERROR;
385 BOOL CALLBACK dconn_FDriverConnectProc(HWND hdlg, UINT wMsg,
386 WPARAM wParam, LPARAM lParam)
388 ConnInfo *ci;
390 switch (wMsg)
392 case WM_INITDIALOG:
393 ci = (ConnInfo *) lParam;
395 /* Change the caption for the setup dialog */
396 SetWindowText(hdlg, "Versaplex Connection");
398 /* Hide the DSN and description fields */
399 ShowWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), SW_HIDE);
400 ShowWindow(GetDlgItem(hdlg, IDC_DSNAME), SW_HIDE);
401 ShowWindow(GetDlgItem(hdlg, IDC_TEST), SW_HIDE);
402 if ('\0' != ci->server[0])
403 EnableWindow(GetDlgItem(hdlg, IDC_SERVER), FALSE);
404 if ('\0' != ci->port[0])
405 EnableWindow(GetDlgItem(hdlg, IDC_PORT), FALSE);
407 SetWindowLongPtr(hdlg, DWLP_USER, lParam); /* Save the ConnInfo for
408 * the "OK" */
409 SetDlgStuff(hdlg, ci);
411 if (ci->database[0] == '\0')
412 ; /* default focus */
413 else if (ci->server[0] == '\0')
414 SetFocus(GetDlgItem(hdlg, IDC_SERVER));
415 else if (ci->port[0] == '\0')
416 SetFocus(GetDlgItem(hdlg, IDC_PORT));
417 else if (ci->username[0] == '\0')
418 SetFocus(GetDlgItem(hdlg, IDC_USER));
419 else if (ci->focus_password)
420 SetFocus(GetDlgItem(hdlg, IDC_PASSWORD));
421 break;
423 case WM_COMMAND:
424 switch (GET_WM_COMMAND_ID(wParam, lParam))
426 case IDOK:
427 ci = (ConnInfo *) GetWindowLongPtr(hdlg, DWLP_USER);
429 GetDlgStuff(hdlg, ci);
431 case IDCANCEL:
432 EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
433 return TRUE;
437 return FALSE;
439 #endif /* WIN32 */
442 typedef BOOL (*copyfunc) (ConnInfo *, const char *attribute,
443 const char *value);
444 static void dconn_get_attributes(copyfunc func,
445 const SQLCHAR FAR * connect_string,
446 ConnInfo * ci)
448 char *our_connect_string;
449 const char *pair, *attribute, *value;
450 char *equals;
451 char *strtok_arg;
452 #ifdef HAVE_STRTOK_R
453 char *last;
454 #endif /* HAVE_STRTOK_R */
456 our_connect_string = strdup((const char *)connect_string);
457 strtok_arg = our_connect_string;
459 #ifdef FORCE_PASSWORD_DISPLAY
460 mylog("our_connect_string = '%s'\n", our_connect_string);
461 #else
462 if (get_mylog())
464 char *hide_str = hide_password(our_connect_string);
466 mylog("our_connect_string = '%s'\n", hide_str);
467 free(hide_str);
469 #endif /* FORCE_PASSWORD_DISPLAY */
471 while (1)
473 #ifdef HAVE_STRTOK_R
474 pair = strtok_r(strtok_arg, ";", &last);
475 #else
476 pair = strtok(strtok_arg, ";");
477 #endif /* HAVE_STRTOK_R */
478 if (strtok_arg)
479 strtok_arg = 0;
480 if (!pair)
481 break;
483 equals = strchr(pair, '=');
484 if (!equals)
485 continue;
487 *equals = '\0';
488 attribute = pair; /* ex. DSN */
489 value = equals + 1; /* ex. 'CEO co1' */
491 #ifndef FORCE_PASSWORD_DISPLAY
492 if (stricmp(attribute, INI_PASSWORD) == 0 ||
493 stricmp(attribute, "pwd") == 0)
494 mylog("attribute = '%s', value = 'xxxxx'\n", attribute);
495 else
496 #endif /* FORCE_PASSWORD_DISPLAY */
497 mylog("attribute = '%s', value = '%s'\n", attribute, value);
499 if (!attribute || !value)
500 continue;
502 /* Copy the appropriate value to the conninfo */
503 (*func) (ci, attribute, value);
507 free(our_connect_string);
510 void dconn_get_connect_attributes(const SQLCHAR FAR * connect_string,
511 ConnInfo * ci)
514 CC_conninfo_init(ci);
515 dconn_get_attributes(copyAttributes, connect_string, ci);
518 static void dconn_get_common_attributes(const SQLCHAR FAR * connect_string,
519 ConnInfo * ci)
521 dconn_get_attributes(copyCommonAttributes, connect_string, ci);