]> granicus.if.org Git - postgresql/blob - src/interfaces/odbc/drvconn.c
781bdd54903eb16f4175912a944d9757dc3f5006
[postgresql] / src / interfaces / odbc / drvconn.c
1 /*-------
2   Module:                       drvconn.c
3  *
4  * Description:         This module contains only routines related to
5  *                                      implementing SQLDriverConnect.
6  *
7  * Classes:                     n/a
8  *
9  * API functions:       SQLDriverConnect
10  *
11  * Comments:            See "notice.txt" for copyright and license information.
12  *-------
13  */
14
15 #include "psqlodbc.h"
16
17 #include <stdio.h>
18 #include <stdlib.h>
19
20 #include "connection.h"
21
22 #ifndef WIN32
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #define NEAR
26 #else
27 #include <winsock.h>
28 #include <sqlext.h>
29 #endif
30
31 #include <string.h>
32
33 #ifndef WIN32
34 #define stricmp(s1,s2)  strcasecmp(s1,s2)
35 #define strnicmp(s1,s2,n)       strncasecmp(s1,s2,n)
36 #else
37 #include <windows.h>
38 #include <windowsx.h>
39 #include <odbcinst.h>
40 #include "resource.h"
41 #endif
42 #include "pgapifunc.h"
43
44 #ifndef TRUE
45 #define TRUE    (BOOL)1
46 #endif
47 #ifndef FALSE
48 #define FALSE   (BOOL)0
49 #endif
50
51 #include "dlg_specific.h"
52
53 /* prototypes */
54 void            dconn_get_connect_attributes(const UCHAR FAR *connect_string, ConnInfo *ci);
55 static void     dconn_get_common_attributes(const UCHAR FAR *connect_string, ConnInfo *ci);
56
57 #ifdef WIN32
58 BOOL FAR PASCAL dconn_FDriverConnectProc(HWND hdlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
59 RETCODE         dconn_DoDialog(HWND hwnd, ConnInfo *ci);
60
61 extern HINSTANCE NEAR s_hModule;/* Saved module handle. */
62
63 #endif
64
65
66 RETCODE SQL_API
67 PGAPI_DriverConnect(
68                                  HDBC hdbc,
69                                  HWND hwnd,
70                                  UCHAR FAR *szConnStrIn,
71                                  SWORD cbConnStrIn,
72                                  UCHAR FAR *szConnStrOut,
73                                  SWORD cbConnStrOutMax,
74                                  SWORD FAR *pcbConnStrOut,
75                                  UWORD fDriverCompletion)
76 {
77         static char *func = "PGAPI_DriverConnect";
78         ConnectionClass *conn = (ConnectionClass *) hdbc;
79         ConnInfo   *ci;
80
81 #ifdef WIN32
82         RETCODE         dialog_result;
83
84 #endif
85         RETCODE         result;
86         char            connStrIn[MAX_CONNECT_STRING];
87         char            connStrOut[MAX_CONNECT_STRING];
88         int                     retval;
89         char            password_required = FALSE;
90         int                     len = 0;
91         SWORD           lenStrout;
92
93
94         mylog("%s: entering...\n", func);
95
96         if (!conn)
97         {
98                 CC_log_error(func, "", NULL);
99                 return SQL_INVALID_HANDLE;
100         }
101
102         make_string(szConnStrIn, cbConnStrIn, connStrIn);
103
104         mylog("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, connStrIn);
105         qlog("conn=%u, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, connStrIn, fDriverCompletion);
106
107         ci = &(conn->connInfo);
108
109         /* Parse the connect string and fill in conninfo for this hdbc. */
110         dconn_get_connect_attributes(connStrIn, ci);
111
112         /*
113          * If the ConnInfo in the hdbc is missing anything, this function will
114          * fill them in from the registry (assuming of course there is a DSN
115          * given -- if not, it does nothing!)
116          */
117         getDSNinfo(ci, CONN_DONT_OVERWRITE);
118         dconn_get_common_attributes(connStrIn, ci);
119         logs_on_off(1, ci->drivers.debug, ci->drivers.commlog);
120
121         /* Fill in any default parameters if they are not there. */
122         getDSNdefaults(ci);
123         /* initialize pg_version */
124         CC_initialize_pg_version(conn);
125
126 #ifdef WIN32
127 dialog:
128 #endif
129         ci->focus_password = password_required;
130
131         switch (fDriverCompletion)
132         {
133 #ifdef WIN32
134                 case SQL_DRIVER_PROMPT:
135                         dialog_result = dconn_DoDialog(hwnd, ci);
136                         if (dialog_result != SQL_SUCCESS)
137                                 return dialog_result;
138                         break;
139
140                 case SQL_DRIVER_COMPLETE_REQUIRED:
141
142                         /* Fall through */
143
144                 case SQL_DRIVER_COMPLETE:
145
146                         /* Password is not a required parameter. */
147                         if (ci->username[0] == '\0' ||
148                                 ci->server[0] == '\0' ||
149                                 ci->database[0] == '\0' ||
150                                 ci->port[0] == '\0' ||
151                                 password_required)
152                         {
153                                 dialog_result = dconn_DoDialog(hwnd, ci);
154                                 if (dialog_result != SQL_SUCCESS)
155                                         return dialog_result;
156                         }
157                         break;
158 #else
159                 case SQL_DRIVER_PROMPT:
160                 case SQL_DRIVER_COMPLETE:
161                 case SQL_DRIVER_COMPLETE_REQUIRED:
162 #endif
163                 case SQL_DRIVER_NOPROMPT:
164                         break;
165         }
166
167         /*
168          * Password is not a required parameter unless authentication asks for
169          * it. For now, I think it's better to just let the application ask
170          * over and over until a password is entered (the user can always hit
171          * Cancel to get out)
172          */
173         if (ci->username[0] == '\0' ||
174                 ci->server[0] == '\0' ||
175                 ci->database[0] == '\0' ||
176                 ci->port[0] == '\0')
177         {
178                 /* (password_required && ci->password[0] == '\0')) */
179
180                 return SQL_NO_DATA_FOUND;
181         }
182
183         /* do the actual connect */
184         retval = CC_connect(conn, password_required);
185         if (retval < 0)
186         {                                                       /* need a password */
187                 if (fDriverCompletion == SQL_DRIVER_NOPROMPT)
188                 {
189                         CC_log_error(func, "Need password but Driver_NoPrompt", conn);
190                         return SQL_ERROR;       /* need a password but not allowed to
191                                                                  * prompt so error */
192                 }
193                 else
194                 {
195 #ifdef WIN32
196                         password_required = TRUE;
197                         goto dialog;
198 #else
199                         return SQL_ERROR;       /* until a better solution is found. */
200 #endif
201                 }
202         }
203         else if (retval == 0)
204         {
205                 /* error msg filled in above */
206                 CC_log_error(func, "Error from CC_Connect", conn);
207                 return SQL_ERROR;
208         }
209
210         /*
211          * Create the Output Connection String
212          */
213         result = SQL_SUCCESS;
214
215         lenStrout = cbConnStrOutMax;
216         if (conn->ms_jet && lenStrout > 255)
217                 lenStrout = 255; 
218         makeConnectString(connStrOut, ci, lenStrout);
219         len = strlen(connStrOut);
220
221         if (szConnStrOut)
222         {
223
224                 /*
225                  * Return the completed string to the caller. The correct method
226                  * is to only construct the connect string if a dialog was put up,
227                  * otherwise, it should just copy the connection input string to
228                  * the output. However, it seems ok to just always construct an
229                  * output string.  There are possible bad side effects on working
230                  * applications (Access) by implementing the correct behavior,
231                  * anyway.
232                  */
233                 strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax);
234
235                 if (len >= cbConnStrOutMax)
236                 {
237                         int     clen;
238                         for (clen = strlen(szConnStrOut) - 1; clen >= 0 && szConnStrOut[clen] != ';'; clen--)
239                                 szConnStrOut[clen] = '\0';
240                         result = SQL_SUCCESS_WITH_INFO;
241                         conn->errornumber = CONN_TRUNCATED;
242                         conn->errormsg = "The buffer was too small for the ConnStrOut.";
243                 }
244         }
245
246         if (pcbConnStrOut)
247                 *pcbConnStrOut = len;
248
249         mylog("szConnStrOut = '%s' len=%d,%d\n", szConnStrOut, len, cbConnStrOutMax);
250         qlog("conn=%u, PGAPI_DriverConnect(out)='%s'\n", conn, szConnStrOut);
251
252
253         mylog("PGAPI_DRiverConnect: returning %d\n", result);
254         return result;
255 }
256
257
258 #ifdef WIN32
259 RETCODE
260 dconn_DoDialog(HWND hwnd, ConnInfo *ci)
261 {
262         int                     dialog_result;
263
264         mylog("dconn_DoDialog: ci = %u\n", ci);
265
266         if (hwnd)
267         {
268                 dialog_result = DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_CONFIG),
269                                                         hwnd, dconn_FDriverConnectProc, (LPARAM) ci);
270                 if (!dialog_result || (dialog_result == -1))
271                         return SQL_NO_DATA_FOUND;
272                 else
273                         return SQL_SUCCESS;
274         }
275
276         return SQL_ERROR;
277 }
278
279
280 BOOL FAR        PASCAL
281 dconn_FDriverConnectProc(
282                                                  HWND hdlg,
283                                                  UINT wMsg,
284                                                  WPARAM wParam,
285                                                  LPARAM lParam)
286 {
287         ConnInfo   *ci;
288
289         switch (wMsg)
290         {
291                 case WM_INITDIALOG:
292                         ci = (ConnInfo *) lParam;
293
294                         /* Change the caption for the setup dialog */
295                         SetWindowText(hdlg, "PostgreSQL Connection");
296
297                         SetWindowText(GetDlgItem(hdlg, IDC_DATASOURCE), "Connection");
298
299                         /* Hide the DSN and description fields */
300                         ShowWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), SW_HIDE);
301                         ShowWindow(GetDlgItem(hdlg, IDC_DSNAME), SW_HIDE);
302                         ShowWindow(GetDlgItem(hdlg, IDC_DESCTEXT), SW_HIDE);
303                         ShowWindow(GetDlgItem(hdlg, IDC_DESC), SW_HIDE);
304
305                         SetWindowLong(hdlg, DWL_USER, lParam);          /* Save the ConnInfo for
306                                                                                                                  * the "OK" */
307                         SetDlgStuff(hdlg, ci);
308
309                         if (ci->database[0] == '\0')
310                                 ;                               /* default focus */
311                         else if (ci->server[0] == '\0')
312                                 SetFocus(GetDlgItem(hdlg, IDC_SERVER));
313                         else if (ci->port[0] == '\0')
314                                 SetFocus(GetDlgItem(hdlg, IDC_PORT));
315                         else if (ci->username[0] == '\0')
316                                 SetFocus(GetDlgItem(hdlg, IDC_USER));
317                         else if (ci->focus_password)
318                                 SetFocus(GetDlgItem(hdlg, IDC_PASSWORD));
319                         break;
320
321                 case WM_COMMAND:
322                         switch (GET_WM_COMMAND_ID(wParam, lParam))
323                         {
324                                 case IDOK:
325                                         ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER);
326
327                                         GetDlgStuff(hdlg, ci);
328
329                                 case IDCANCEL:
330                                         EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
331                                         return TRUE;
332
333                                 case IDC_DRIVER:
334                                         ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER);
335                                         DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DRV),
336                                                                 hdlg, driver_optionsProc, (LPARAM) ci);
337                                         break;
338
339                                 case IDC_DATASOURCE:
340                                         ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER);
341                                         DialogBoxParam(s_hModule, MAKEINTRESOURCE(DLG_OPTIONS_DS),
342                                                                    hdlg, ds_optionsProc, (LPARAM) ci);
343                                         break;
344                         }
345         }
346
347         return FALSE;
348 }
349
350 #endif   /* WIN32 */
351
352
353 void
354 dconn_get_connect_attributes(const UCHAR FAR *connect_string, ConnInfo *ci)
355 {
356         char       *our_connect_string;
357         char       *pair,
358                            *attribute,
359                            *value,
360                            *equals;
361         char       *strtok_arg;
362
363         memset(ci, 0, sizeof(ConnInfo));
364
365         our_connect_string = strdup(connect_string);
366         strtok_arg = our_connect_string;
367
368         mylog("our_connect_string = '%s'\n", our_connect_string);
369
370         while (1)
371         {
372                 pair = strtok(strtok_arg, ";");
373                 if (strtok_arg)
374                         strtok_arg = 0;
375                 if (!pair)
376                         break;
377
378                 equals = strchr(pair, '=');
379                 if (!equals)
380                         continue;
381
382                 *equals = '\0';
383                 attribute = pair;               /* ex. DSN */
384                 value = equals + 1;             /* ex. 'CEO co1' */
385
386                 mylog("attribute = '%s', value = '%s'\n", attribute, value);
387
388                 if (!attribute || !value)
389                         continue;
390
391                 /* Copy the appropriate value to the conninfo  */
392                 copyAttributes(ci, attribute, value);
393
394         }
395
396         free(our_connect_string);
397 }
398
399 static void
400 dconn_get_common_attributes(const UCHAR FAR *connect_string, ConnInfo *ci)
401 {
402         char       *our_connect_string;
403         char       *pair,
404                            *attribute,
405                            *value,
406                            *equals;
407         char       *strtok_arg;
408
409         our_connect_string = strdup(connect_string);
410         strtok_arg = our_connect_string;
411
412         mylog("our_connect_string = '%s'\n", our_connect_string);
413
414         while (1)
415         {
416                 pair = strtok(strtok_arg, ";");
417                 if (strtok_arg)
418                         strtok_arg = 0;
419                 if (!pair)
420                         break;
421
422                 equals = strchr(pair, '=');
423                 if (!equals)
424                         continue;
425
426                 *equals = '\0';
427                 attribute = pair;               /* ex. DSN */
428                 value = equals + 1;             /* ex. 'CEO co1' */
429
430                 mylog("attribute = '%s', value = '%s'\n", attribute, value);
431
432                 if (!attribute || !value)
433                         continue;
434
435                 /* Copy the appropriate value to the conninfo  */
436                 copyCommonAttributes(ci, attribute, value);
437
438         }
439
440         free(our_connect_string);
441 }