1 /*
2  *  drvconn.c
3  *
4  *  $Id$
5  *
6  *  The data_sources dialog for SQLDriverConnect
7  *
8  *  The iODBC driver manager.
9  *
10  *  Copyright (C) 1996-2021 OpenLink Software <iodbc@openlinksw.com>
11  *  All Rights Reserved.
12  *
13  *  This software is released under the terms of either of the following
14  *  licenses:
15  *
16  *      - GNU Library General Public License (see LICENSE.LGPL)
17  *      - The BSD License (see LICENSE.BSD).
18  *
19  *  Note that the only valid version of the LGPL license as far as this
20  *  project is concerned is the original GNU Library General Public License
21  *  Version 2, dated June 1991.
22  *
23  *  While not mandated by the BSD license, any patches you make to the
24  *  iODBC source code may be contributed back into the iODBC project
25  *  at your discretion. Contributions will benefit the Open Source and
26  *  Data Access community as a whole. Submissions may be made at:
27  *
28  *      http://www.iodbc.org
29  *
30  *
31  *  GNU Library Generic Public License Version 2
32  *  ============================================
33  *  This library is free software; you can redistribute it and/or
34  *  modify it under the terms of the GNU Library General Public
35  *  License as published by the Free Software Foundation; only
36  *  Version 2 of the License dated June 1991.
37  *
38  *  This library is distributed in the hope that it will be useful,
39  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
40  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
41  *  Library General Public License for more details.
42  *
43  *  You should have received a copy of the GNU Library General Public
44  *  License along with this library; if not, write to the Free
45  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
46  *
47  *
48  *  The BSD License
49  *  ===============
50  *  Redistribution and use in source and binary forms, with or without
51  *  modification, are permitted provided that the following conditions
52  *  are met:
53  *
54  *  1. Redistributions of source code must retain the above copyright
55  *     notice, this list of conditions and the following disclaimer.
56  *  2. Redistributions in binary form must reproduce the above copyright
57  *     notice, this list of conditions and the following disclaimer in
58  *     the documentation and/or other materials provided with the
59  *     distribution.
60  *  3. Neither the name of OpenLink Software Inc. nor the names of its
61  *     contributors may be used to endorse or promote products derived
62  *     from this software without specific prior written permission.
63  *
64  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
65  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
66  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
67  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR
68  *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
69  *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
70  *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
71  *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
72  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
73  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
74  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
75  */
76 
77 
78 #include "gui.h"
79 
80 #include "herr.h"
81 #include "unicode.h"
82 #include "dlproc.h"
83 
84 #ifndef WIN32
85 #include <unistd.h>
86 
87 typedef SQLRETURN SQL_API (*pDriverConnFunc) (HWND hwnd, LPSTR szInOutConnStr,
88     DWORD cbInOutConnStr, int FAR * sqlStat, SQLUSMALLINT fDriverCompletion, UWORD *config);
89 typedef SQLRETURN SQL_API (*pDriverConnWFunc) (HWND hwnd, LPWSTR szInOutConnStr,
90     DWORD cbInOutConnStr, int FAR * sqlStat, SQLUSMALLINT fDriverCompletion, UWORD *config);
91 
92 #if defined (__APPLE__)
93 
94 #define CALL_DRVCONN_DIALBOXW(path, a) \
95     if (path) \
96     { \
97        char *_path_u8 = (a == 'A') ? strdup((const char *)path) : (char*)dm_SQL_W2A ((wchar_t*)path, SQL_NTS); \
98        if (_path_u8) { \
99          char *ptr = strstr(_path_u8, "/Contents/MacOS/"); \
100          if (ptr) \
101            *ptr = 0; \
102          liburl = CFURLCreateFromFileSystemRepresentation (NULL, (UInt8*)_path_u8, strlen(_path_u8), FALSE); \
103 		 CFArrayRef arr = CFBundleCopyExecutableArchitecturesForURL(liburl); \
104 		 if (arr) \
105            bundle_dll = CFBundleCreate (NULL, liburl); \
106          if (arr) \
107            CFRelease(arr); \
108          if (liburl) \
109            CFRelease(liburl); \
110        } \
111        MEM_FREE(_path_u8); \
112        CALL_DRVCONN_DIALBOXW_BUNDLE(); \
113     }
114 
115 
116 #define CALL_DRVCONN_DIALBOXW_BUNDLE() \
117     if (bundle_dll != NULL) \
118       { \
119         if ((pDrvConnW = (pDriverConnWFunc)CFBundleGetFunctionPointerForName(bundle_dll, CFSTR("_iodbcdm_drvconn_dialboxw"))) != NULL) \
120           { \
121             SQLSetConfigMode (*config); \
122             if (pDrvConnW (hwnd, szInOutConnStr, cbInOutConnStr, sqlStat, fDriverCompletion, config) == SQL_SUCCESS) \
123               { \
124                 retcode = SQL_SUCCESS; \
125                 goto quit; \
126               } \
127             else \
128               { \
129                 retcode = SQL_NO_DATA_FOUND; \
130                 goto quit; \
131               } \
132           } \
133         else \
134           { \
135             if ((pDrvConn = (pDriverConnFunc)CFBundleGetFunctionPointerForName(bundle_dll, CFSTR("_iodbcdm_drvconn_dialbox"))) != NULL) \
136               { \
137                 char *_szinoutconstr_u8 = malloc (cbInOutConnStr + 1); \
138                 wchar_t *_prvw; char *_prvu8; \
139                 for (_prvw = szInOutConnStr, _prvu8 = _szinoutconstr_u8 ; \
140                   *_prvw != L'\0' ; _prvw += WCSLEN (_prvw) + 1, \
141                   _prvu8 += STRLEN (_prvu8) + 1) \
142                   dm_StrCopyOut2_W2A (_prvw, (SQLCHAR *)_prvu8, cbInOutConnStr, NULL); \
143                   *_prvu8 = '\0'; \
144                 SQLSetConfigMode (*config); \
145                 if (pDrvConn (hwnd, _szinoutconstr_u8, cbInOutConnStr, sqlStat, fDriverCompletion, config) == SQL_SUCCESS) \
146                   { \
147                     dm_StrCopyOut2_A2W ((SQLCHAR *)_szinoutconstr_u8, szInOutConnStr, cbInOutConnStr, NULL); \
148                     MEM_FREE (_szinoutconstr_u8); \
149                     retcode = SQL_SUCCESS; \
150                     goto quit; \
151                   } \
152                 else \
153                   { \
154                     MEM_FREE (_szinoutconstr_u8); \
155                     retcode = SQL_NO_DATA_FOUND; \
156                     goto quit; \
157                   } \
158               } \
159           } \
160       }
161 
162 #else
163 
164 #define CALL_DRVCONN_DIALBOXW(path, a) \
165   { \
166     char *_path_u8 = (a == 'A') ? NULL : dm_SQL_W2A ((wchar_t*)path, SQL_NTS); \
167     if ((handle = DLL_OPEN((a == 'A') ? (char*)path : _path_u8)) != NULL) \
168       { \
169         if ((pDrvConnW = (pDriverConnWFunc)DLL_PROC(handle, "_iodbcdm_drvconn_dialboxw")) != NULL) \
170           { \
171             SQLSetConfigMode (*config); \
172             if (pDrvConnW (hwnd, szInOutConnStr, cbInOutConnStr, sqlStat, fDriverCompletion, config) == SQL_SUCCESS) \
173               { \
174                 MEM_FREE (_path_u8); \
175                 DLL_CLOSE(handle); \
176                 retcode = SQL_SUCCESS; \
177                 goto quit; \
178               } \
179             else \
180               { \
181                 MEM_FREE (_path_u8); \
182                 DLL_CLOSE(handle); \
183                 retcode = SQL_NO_DATA_FOUND; \
184                 goto quit; \
185               } \
186           } \
187         else \
188           { \
189             if ((pDrvConn = (pDriverConnFunc)DLL_PROC(handle, "_iodbcdm_drvconn_dialbox")) != NULL) \
190               { \
191                 char *_szinoutconstr_u8 = malloc (cbInOutConnStr + 1); \
192                 wchar_t *_prvw; char *_prvu8; \
193                 for (_prvw = szInOutConnStr, _prvu8 = _szinoutconstr_u8 ; \
194                   *_prvw != L'\0' ; _prvw += WCSLEN (_prvw) + 1, \
195                   _prvu8 += STRLEN (_prvu8) + 1) \
196                   dm_StrCopyOut2_W2A (_prvw, _prvu8, cbInOutConnStr, NULL); \
197                 *_prvu8 = '\0'; \
198                 SQLSetConfigMode (*config); \
199                 if (pDrvConn (hwnd, _szinoutconstr_u8, cbInOutConnStr, sqlStat, fDriverCompletion, config) == SQL_SUCCESS) \
200                   { \
201                     dm_StrCopyOut2_A2W (_szinoutconstr_u8, szInOutConnStr, cbInOutConnStr, NULL); \
202                     MEM_FREE (_path_u8); \
203                     MEM_FREE (_szinoutconstr_u8); \
204                     DLL_CLOSE(handle); \
205                     retcode = SQL_SUCCESS; \
206                     goto quit; \
207                   } \
208                 else \
209                   { \
210                     MEM_FREE (_path_u8); \
211                     MEM_FREE (_szinoutconstr_u8); \
212                     DLL_CLOSE(handle); \
213                     retcode = SQL_NO_DATA_FOUND; \
214                     goto quit; \
215                   } \
216               } \
217           } \
218         DLL_CLOSE(handle); \
219       } \
220     MEM_FREE (_path_u8); \
221   }
222 #endif
223 
224 #endif
225 
226 SQLRETURN SQL_API
227 iodbcdm_drvconn_dialbox (
228     HWND hwnd,
229     LPSTR szInOutConnStr,
230     DWORD cbInOutConnStr,
231     int * sqlStat,
232     SQLUSMALLINT fDriverCompletion,
233     UWORD *config)
234 {
235   RETCODE retcode = SQL_ERROR;
236   wchar_t *_string_w = NULL;
237 
238   if (cbInOutConnStr > 0)
239     {
240       if ((_string_w = malloc (cbInOutConnStr * sizeof(wchar_t) + 1)) == NULL)
241           goto done;
242     }
243 
244   dm_StrCopyOut2_A2W ((SQLCHAR*)szInOutConnStr, _string_w,
245     cbInOutConnStr * sizeof(wchar_t), NULL);
246 
247   retcode = iodbcdm_drvconn_dialboxw (hwnd, _string_w,
248     cbInOutConnStr, sqlStat, fDriverCompletion, config);
249 
250   if (retcode == SQL_SUCCESS)
251     {
252       dm_StrCopyOut2_W2A (_string_w, (SQLCHAR*)szInOutConnStr, cbInOutConnStr - 1, NULL);
253     }
254 
255 done:
256   MEM_FREE (_string_w);
257 
258   return retcode;
259 }
260 
261 
262 SQLRETURN SQL_API
263 iodbcdm_drvconn_dialboxw (
264     HWND hwnd,
265     LPWSTR szInOutConnStr,
266     DWORD cbInOutConnStr,
267     int * sqlStat,
268     SQLUSMALLINT fDriverCompletion,
269 	 UWORD *config)
270 {
271   RETCODE retcode = SQL_ERROR;
272   TDSNCHOOSER choose_t;
273   wchar_t *string = NULL, *prov, *prov1, *szDSN = NULL, *szDriver = NULL;
274   wchar_t *szFILEDSN = NULL, *szSAVEFILE = NULL;
275   wchar_t tokenstr[4096];
276   wchar_t drvbuf[4096] = { L'\0'};
277   char *_szdriver_u8 = NULL;
278   wchar_t *_szdriver_w = NULL;
279   HDLL handle;
280   pDriverConnFunc pDrvConn;
281   pDriverConnWFunc pDrvConnW;
282   int i, skip;
283 #if defined (__APPLE__) && !defined (NO_FRAMEWORKS)
284   CFBundleRef bundle = NULL;
285   CFBundleRef bundle_dll = NULL;
286   CFURLRef liburl = NULL;
287 #endif
288 
289 
290   memset(&choose_t, 0, sizeof(choose_t));
291   /* Check input parameters */
292   if (!szInOutConnStr || cbInOutConnStr < 1)
293     goto quit;
294 
295   /* Transform the string connection to list of key pairs */
296   string = (wchar_t*) malloc((cbInOutConnStr + 1) * sizeof(wchar_t));
297   if (string == NULL)
298     {
299       if (sqlStat)
300 #if (ODBCVER>=0x3000)
301         *sqlStat = en_HY092;
302 #else
303         *sqlStat = en_S1000;
304 #endif
305       retcode = SQL_ERROR;
306       goto quit;
307     }
308 
309   /* Conversion to the list of key pairs */
310   wcsncpy (string, szInOutConnStr, cbInOutConnStr);
311   string[WCSLEN (string) + 1] = L'\0';
312   skip = 0;
313   for (i = WCSLEN (string) - 1 ; i >= 0 ; i--)
314   {
315     if (string[i] == L'}')
316       skip = 1;
317     else if (string[i] == L'{')
318       skip = 0;
319     else if (skip == 0 && string[i] == L';') string[i] = L'\0';
320   }
321 
322   /* Look for the DSN and DRIVER keyword */
323   for (prov = string ; *prov != L'\0' ; prov += WCSLEN (prov) + 1)
324     {
325       if (!wcsncasecmp (prov, L"DSN=", WCSLEN (L"DSN=")))
326         {
327           szDSN = prov + WCSLEN (L"DSN=");
328           continue;
329         }
330       if (!wcsncasecmp (prov, L"DRIVER=", WCSLEN (L"DRIVER=")))
331         {
332           szDriver = prov + WCSLEN (L"DRIVER=");
333           continue;
334         }
335       if (!wcsncasecmp (prov, L"FILEDSN=", WCSLEN (L"FILEDSN=")))
336         {
337           szFILEDSN = prov + WCSLEN (L"FILEDSN=");
338           continue;
339         }
340       if (!wcsncasecmp (prov, L"SAVEFILE=", WCSLEN (L"SAVEFILE=")))
341         {
342           szSAVEFILE = prov + WCSLEN (L"SAVEFILE=");
343           continue;
344         }
345     }
346 
347   if (!szDSN && !szDriver)
348     {
349       /* Initialize members in case of early create_dsnchooser return */
350       choose_t.dsn = NULL;
351       choose_t.fdsn = NULL;
352 
353       /* Display the DSN chooser dialog box */
354       create_dsnchooser (hwnd, &choose_t);
355 
356       /* Check output parameters */
357       if (choose_t.dsn || choose_t.fdsn)
358         {
359 #if (ODBCVER>=0x3000)
360           int errSqlStat = en_HY092;
361 #else
362           int errSqlStat = en_HY092;
363 #endif
364           /* Change the config mode */
365           switch (choose_t.type_dsn)
366             {
367               case USER_DSN:
368                 *config = ODBC_USER_DSN;
369                 break;
370               case SYSTEM_DSN:
371                 *config = ODBC_SYSTEM_DSN;
372                 break;
373             };
374 
375           if (choose_t.dsn && (choose_t.type_dsn == USER_DSN || choose_t.type_dsn == SYSTEM_DSN))
376             {
377               /* Try to copy the DSN */
378               if (cbInOutConnStr > WCSLEN (choose_t.dsn) + WCSLEN (L"DSN=") + 2)
379                 {
380                   WCSCPY (string, L"DSN=");
381                   WCSCAT (string, choose_t.dsn);
382                   string[WCSLEN (string) + 1] = L'\0';
383                   szDSN = string + WCSLEN (L"DSN=");
384                   retcode = SQL_SUCCESS;
385                 }
386               else
387                 {
388                   if (sqlStat)
389                     *sqlStat = errSqlStat;
390                 }
391             }
392           else if (choose_t.fdsn && choose_t.type_dsn == FILE_DSN)
393             {
394               DWORD sz, sz_entry;
395               wchar_t entries[4096];
396               WORD read_len;
397               wchar_t *p, *p_next;
398 
399               sz = WCSLEN(choose_t.fdsn) + WCSLEN(L"FILEDSN=") + 2;
400               if (cbInOutConnStr > sz)
401                 {
402                   WCSCPY (string, L"FILEDSN=");
403                   WCSCAT (string, choose_t.fdsn);
404                   WCSCAT (string, L";");
405                   retcode = SQL_SUCCESS;
406                 }
407 
408               /* Get list of entries in .dsn file */
409               if (retcode == SQL_SUCCESS
410                   && SQLReadFileDSNW (choose_t.fdsn, L"ODBC", NULL,
411 		       entries, sizeof (entries)/sizeof(wchar_t), &read_len))
412                 {
413                   /* add params from the .dsn file */
414                   for (p = entries; *p != '\0'; p = p_next)
415                     {
416                       wchar_t value[1024];
417 
418                       /* get next entry */
419                       p_next = wcschr (p, L';');
420                       if (p_next)
421                         *p_next++ = L'\0';
422 
423                       if (!SQLReadFileDSNW (choose_t.fdsn, L"ODBC", p, value,
424                               sizeof(value)/sizeof(wchar_t), &read_len))
425                         {
426                           retcode = SQL_ERROR;
427                           break;
428                         }
429 
430                       if (!wcsncasecmp (p, L"DRIVER", WCSLEN(L"DRIVER")))
431                         {
432                           szDriver = _szdriver_w = (wchar_t*) malloc((WCSLEN(value) + 1) * sizeof(wchar_t));
433                           if (szDriver)
434                             WCSCPY(szDriver, value);
435                         }
436 
437                       sz_entry = WCSLEN(p) + 1 + WCSLEN(value) + 2;
438                       if (cbInOutConnStr > sz + sz_entry)
439                         {
440                           WCSCAT (string, p);
441                           WCSCAT (string, L"=");
442                           WCSCAT (string, value);
443                           WCSCAT (string, L";");
444                           sz += sz_entry;
445                         }
446                       else
447                         {
448                           retcode = SQL_ERROR;
449                         }
450                     }
451                 }
452               if (retcode == SQL_SUCCESS)
453                 {
454                   string[WCSLEN (string) + 1] = L'\0';
455                   for (i = WCSLEN (string) - 1 ; i >= 0 ; i--)
456                     if (string[i] == L';') string[i] = L'\0';
457                 }
458               else if (sqlStat)
459                 *sqlStat = errSqlStat;
460             }
461           else
462             {
463               if (sqlStat)
464                 *sqlStat = errSqlStat;
465             }
466         }
467       else
468         retcode = SQL_NO_DATA_FOUND;
469 
470       if (choose_t.dsn)
471 	free (choose_t.dsn);
472       if (choose_t.fdsn)
473 	free (choose_t.fdsn);
474 
475       if (retcode != SQL_SUCCESS)
476 	goto quit;
477     }
478 
479 
480   /* Constitute the string connection */
481   for (prov = szInOutConnStr, prov1 = string, i = 0 ; *prov1 != L'\0' ;
482     prov1 += WCSLEN (prov) + 1, i += WCSLEN (prov) + 1, prov += WCSLEN (prov) + 1)
483     WCSCPY (prov, prov1);
484   *prov = L'\0';
485 
486   /* Check if the driver is provided */
487   if (szDriver == NULL)
488     {
489       SQLSetConfigMode (ODBC_BOTH_DSN);
490       SQLGetPrivateProfileStringW (L"ODBC Data Sources",
491         szDSN && szDSN[0] != L'\0' ? szDSN : L"default",
492         L"", tokenstr, sizeof (tokenstr)/sizeof(wchar_t), NULL);
493       szDriver = tokenstr;
494     }
495 
496   /* Call the iodbcdm_drvconn_dialbox */
497   _szdriver_u8 = (char *)dm_SQL_W2A (szDriver, SQL_NTS);
498 
499   SQLSetConfigMode (ODBC_USER_DSN);
500   if (!access (_szdriver_u8, X_OK))
501     { CALL_DRVCONN_DIALBOXW (_szdriver_u8, 'A'); }
502   if (SQLGetPrivateProfileStringW (szDriver, L"Driver", L"", drvbuf,
503     sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
504     { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
505   if (SQLGetPrivateProfileStringW (szDriver, L"Setup", L"", drvbuf,
506     sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
507     { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
508   if (SQLGetPrivateProfileStringW (L"Default", L"Driver", L"", drvbuf,
509     sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
510     { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
511   if (SQLGetPrivateProfileStringW (L"Default", L"Setup", L"", drvbuf,
512     sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
513     { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
514 
515   SQLSetConfigMode (ODBC_SYSTEM_DSN);
516   if (!access (_szdriver_u8, X_OK))
517     { CALL_DRVCONN_DIALBOXW (_szdriver_u8, 'A'); }
518   if (SQLGetPrivateProfileStringW (szDriver, L"Driver", L"", drvbuf,
519     sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
520     { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
521   if (SQLGetPrivateProfileStringW (szDriver, L"Setup", L"", drvbuf,
522     sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
523     { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
524   if (SQLGetPrivateProfileStringW (L"Default", L"Driver", L"", drvbuf,
525     sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
526     { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
527   if (SQLGetPrivateProfileStringW (L"Default", L"Setup", L"", drvbuf,
528     sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
529     { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
530 
531   /* The last ressort, a proxy driver */
532 #if defined (__APPLE__)
533 # if !defined(NO_FRAMEWORKS)
534   bundle = CFBundleGetBundleWithIdentifier (CFSTR ("org.iodbc.core"));
535   if (bundle)
536     {
537       /* Search for the drvproxy library */
538       liburl =
539 	    CFBundleCopyResourceURL (bundle, CFSTR ("iODBCdrvproxy.bundle"),
540 	      NULL, NULL);
541       if (liburl)
542 	  {
543             bundle_dll = CFBundleCreate (NULL, liburl);
544             CFRelease(liburl);
545             CALL_DRVCONN_DIALBOXW_BUNDLE();
546 	  }
547     }
548 # endif
549 #else
550 
551   CALL_DRVCONN_DIALBOXW ("libdrvproxy.so.2", 'A');
552 #endif
553 
554   if (sqlStat)
555     *sqlStat = en_IM003;
556 
557 quit:
558 
559   MEM_FREE (string);
560   MEM_FREE (_szdriver_u8);
561   MEM_FREE (_szdriver_w);
562 
563   return retcode;
564 }
565 
566 
567 SQLRETURN SQL_API
568 _iodbcdm_drvchoose_dialbox (
569     HWND hwnd,
570     LPSTR szInOutConnStr,
571     DWORD cbInOutConnStr,
572     int * sqlStat)
573 {
574   RETCODE retcode = SQL_ERROR;
575   wchar_t *_string_w = NULL;
576   WORD len;
577 
578   if (cbInOutConnStr > 0)
579     {
580       if ((_string_w = malloc ((cbInOutConnStr + 1) * sizeof(wchar_t))) == NULL)
581           goto done;
582     }
583 
584   retcode = _iodbcdm_drvchoose_dialboxw (hwnd, _string_w,
585     cbInOutConnStr * sizeof(wchar_t), sqlStat);
586 
587   if (retcode == SQL_SUCCESS)
588     {
589       dm_StrCopyOut2_W2A (_string_w, (SQLCHAR*)szInOutConnStr, cbInOutConnStr - 1, &len);
590     }
591 
592 done:
593   MEM_FREE (_string_w);
594 
595   return retcode;
596 }
597 
598 
599 SQLRETURN SQL_API
600 _iodbcdm_drvchoose_dialboxw (HWND hwnd,
601     LPWSTR szInOutConnStr,
602     DWORD cbInOutConnStr,
603     int FAR * sqlStat)
604 {
605   RETCODE retcode = SQL_ERROR;
606   TDRIVERCHOOSER choose_t;
607 
608   /* Check input parameters */
609   if (!hwnd || !szInOutConnStr || cbInOutConnStr < 1)
610     goto quit;
611 
612   create_driverchooser (hwnd, &choose_t);
613 
614   /* Check output parameters */
615   if (choose_t.driver)
616     {
617       if (cbInOutConnStr > WCSLEN (choose_t.driver) + WCSLEN (L"DRIVER="))
618 	{
619           WCSCPY (szInOutConnStr, L"DRIVER=");
620           WCSCAT (szInOutConnStr, choose_t.driver);
621 	  retcode = SQL_SUCCESS;
622 	}
623       else
624 	{
625 	  if (sqlStat)
626 #if (ODBCVER>=0x3000)
627 	    *sqlStat = en_HY092;
628 #else
629 	    *sqlStat = en_S1000;
630 #endif
631 	  retcode = SQL_ERROR;
632 	}
633     }
634   else
635     retcode = SQL_NO_DATA;
636 
637   if (choose_t.driver)
638     free (choose_t.driver);
639 
640 quit:
641   return retcode;
642 }
643 
644 
645 SQLRETURN SQL_API
646 _iodbcdm_admin_dialbox (HWND hwnd)
647 {
648   RETCODE retcode = SQL_ERROR;
649 
650   /* Check input parameters */
651   if (!hwnd)
652     goto quit;
653 
654   create_administrator (hwnd);
655   retcode = SQL_SUCCESS;
656 
657 quit:
658   return retcode;
659 }
660 
661 
662 SQLRETURN SQL_API
663 _iodbcdm_trschoose_dialbox (
664     HWND hwnd,
665     LPSTR szInOutConnStr,
666     DWORD cbInOutConnStr,
667     int FAR * sqlStat)
668 {
669   RETCODE retcode = SQL_ERROR;
670   wchar_t *_string_w = NULL;
671   WORD len;
672 
673   if (cbInOutConnStr > 0)
674     {
675       if ((_string_w = malloc ((cbInOutConnStr + 1) * sizeof(wchar_t))) == NULL)
676           goto done;
677     }
678 
679   retcode = _iodbcdm_trschoose_dialboxw (hwnd, _string_w,
680     cbInOutConnStr * sizeof(wchar_t), sqlStat);
681 
682   if (retcode == SQL_SUCCESS)
683     {
684       dm_StrCopyOut2_W2A (_string_w, (SQLCHAR*)szInOutConnStr, cbInOutConnStr - 1, &len);
685     }
686 
687 done:
688   MEM_FREE (_string_w);
689 
690   return retcode;
691 }
692 
693 
694 SQLRETURN SQL_API
695 _iodbcdm_trschoose_dialboxw (
696     HWND hwnd,
697     LPWSTR szInOutConnStr,
698     DWORD cbInOutConnStr,
699     int * sqlStat)
700 {
701   RETCODE retcode = SQL_ERROR;
702   TTRANSLATORCHOOSER choose_t;
703 
704   /* Check input parameters */
705   if (!hwnd || !szInOutConnStr || cbInOutConnStr < 1)
706     goto quit;
707 
708   create_translatorchooser (hwnd, &choose_t);
709 
710   /* Check output parameters */
711   if (choose_t.translator)
712     {
713       if (cbInOutConnStr >
714           WCSLEN (choose_t.translator) + WCSLEN (L"TranslationName="))
715 	{
716           WCSCPY (szInOutConnStr, L"TranslationName");
717           WCSCAT (szInOutConnStr, choose_t.translator);
718 	  retcode = SQL_SUCCESS;
719 	}
720       else
721 	{
722 	  if (sqlStat)
723 #if (ODBCVER>=0x3000)
724 	    *sqlStat = en_HY092;
725 #else
726 	    *sqlStat = en_S1000;
727 #endif
728 	  retcode = SQL_ERROR;
729 	}
730     }
731   else
732     retcode = SQL_NO_DATA;
733 
734   if (choose_t.translator)
735     free (choose_t.translator);
736 
737 quit:
738   return retcode;
739 }
740 
741 
742