NCBI C++ ToolKit
winsetup.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2  * Copyright (C) 2004 Frediano Ziglio
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 /*
21  * PROGRAMMER NAME CONTACT
22  *==============================================================
23  * SJK Steve Kirkendall kirkenda@cs.pdx.edu
24  *
25  ***************************************************************
26  * DATE PROGRAMMER CHANGE
27  *==============================================================
28  * 25.FEB.04 SJK Original.
29  */
30 
31 /* This file implements the setup API for FreeTDS. Specifically,
32  * this includes the ConfigDSN() and ConfigDriver() functions.
33  */
34 
35 #include <config.h>
36 
37 #include <stdarg.h>
38 #include <stdio.h>
39 
40 #if HAVE_STDLIB_H
41 #include <stdlib.h>
42 #endif /* HAVE_STDLIB_H */
43 
44 #if HAVE_STRING_H
45 #include <string.h>
46 #endif /* HAVE_STRING_H */
47 
48 #include <assert.h>
49 #include <ctype.h>
50 #include <assert.h>
51 
52 #include "resource.h"
53 
54 #include <freetds/tds.h>
55 #include <freetds/odbc.h>
56 #include <freetds/string.h>
57 #include <freetds/convert.h>
58 #include "replacements.h"
59 
60 #include <olectl.h>
61 
62 typedef struct
63 {
64  DSTR origdsn; /**< original name of the data source */
65  DSTR dsn; /**< edited name of the data source */
66  TDSLOGIN *login; /**< everything else */
67 } DSNINFO;
68 
69 /* This is defined in ... */
70 extern HINSTANCE hinstFreeTDS;
71 
72 
73 /** Create an empty DSNINFO struct */
74 static DSNINFO *
76 {
77  DSNINFO *di;
78 
79  /* allocate & initialize it */
80  di = (DSNINFO *) malloc(sizeof(DSNINFO));
81  tds_dstr_init(&di->origdsn);
82  tds_dstr_init(&di->dsn);
83  di->login = tds_alloc_login(0);
85 
86  return di;
87 }
88 
89 
90 /** Destroy a DSNINFO struct, freeing all memory associated with it */
91 static void
93 { /* the DSNINFO struct to be freed */
94  tds_free_login(di->login);
95  tds_dstr_free(&di->origdsn);
96  tds_dstr_free(&di->dsn);
97  free(di);
98 }
99 
100 
101 /**
102  * Parse a DSN string which is delimited with NULs instead of semicolons.
103  * This uses odbc_parse_connect_string() internally, and also adds support
104  * for parsing the DSN and driver
105  * \param attribs 0-delimited string, with \0\0 terminator
106  * \param di where to store the results
107  */
108 static void
110 {
111  LPCSTR str;
112  char *build;
113 
114  /* for each field... */
115  for (str = attribs; *str; str += strlen(str) + 1) {
116  if (!strncasecmp(str, "DSN=", 4)) {
117  tds_dstr_copy(&di->origdsn, str + 4);
118  tds_dstr_copy(&di->dsn, str + 4);
119  }
120  }
121 
122  /* allocate space for a ;-delimited version */
123  build = (char *) malloc(str - attribs);
124 
125  /* copy the fields into the new buffer with ;'s */
126  *build = '\0';
127  for (str = attribs; *str; str += strlen(str) + 1) {
128  if (*build)
129  strcat(build, ";");
130  strcat(build, str);
131  }
132 
133  /* let odbc_parse_connect_string() parse the ;-delimited version */
134  odbc_parse_connect_string(NULL, build, build + strlen(build), di->login, NULL);
135 }
136 
137 
138 /**
139  * Update the attributes. Return TRUE if successful, else FALSE. The names
140  * written here correspond to the names read by odbc_get_dsn_info().
141  */
142 #define WRITESTR(n,s) if (!SQLWritePrivateProfileString(section, (n), (s), odbcini)) return FALSE
143 #define FIELD_STRING(f) tds_dstr_cstr(&di->login->f)
144 static BOOL
146 {
147  char odbcini[FILENAME_MAX];
148  char tmp[100];
149  const char *section = tds_dstr_cstr(&di->dsn);
150 
151  strcpy(odbcini, "odbc.ini");
152 
153  WRITESTR("Server", FIELD_STRING(server_name));
154  WRITESTR("Language", FIELD_STRING(language));
155  WRITESTR("Database", FIELD_STRING(database));
156 
157  sprintf(tmp, "%u", di->login->port);
158  WRITESTR("Port", tmp);
159 
160  sprintf(tmp, "%d.%d", TDS_MAJOR(di->login), TDS_MINOR(di->login));
161  WRITESTR("TDS_Version", tmp);
162 
163  sprintf(tmp, "%u", di->login->text_size);
164  WRITESTR("TextSize", tmp);
165 
166  sprintf(tmp, "%u", di->login->block_size);
167  WRITESTR("PacketSize", tmp);
168 
169  return TRUE;
170 }
171 
172 
173 
174 /**
175  * Go looking for trouble. Return NULL if the info is okay, or an error message
176  * if something needs to change.
177  */
178 static const char *
180 {
181  if (!SQLValidDSN(tds_dstr_cstr(&di->dsn)))
182  return "Invalid DSN";
183  if (!IS_TDS42(di->login) && !IS_TDS46(di->login)
184  && !IS_TDS50(di->login) && !IS_TDS7_PLUS(di->login))
185  return "Bad Protocol version";
187  return "Address is required";
188  if (di->login->port < 1 || di->login->port > 65535)
189  return "Bad port - Try 1433 or 4000";
190  return NULL;
191 }
192 
193 #ifndef _WIN64
194 #define GetWindowUserData(wnd) GetWindowLong((wnd), GWL_USERDATA)
195 #define SetWindowUserData(wnd, data) SetWindowLong((wnd), GWL_USERDATA, (data))
196 #else
197 #define GetWindowUserData(wnd) GetWindowLongPtr((wnd), GWLP_USERDATA)
198 #define SetWindowUserData(wnd, data) SetWindowLongPtr((wnd), GWLP_USERDATA, (data))
199 #endif
200 
201 /**
202  * Callback function for the DSN Configuration dialog
203  * \param hDlg identifies the dialog
204  * \param message what happened to the dialog
205  * \param wParam varies with message
206  * \param lParam pointer to DSNINFO struct
207  */
208 static BOOL CALLBACK
209 DSNDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
210 {
211  DSNINFO *di;
212  char tmp[100];
213  const char *pstr;
214  int major, minor, i;
215  static const char *protocols[] = {
216  "TDS 4.2", "TDS 4.6", "TDS 5.0", "TDS 7.0", "TDS 7.1", "TDS 7.2", "TDS 7.3", "TDS 7.4", NULL
217  };
218 
219  switch (message) {
220 
221  case WM_INITDIALOG:
222  /* lParam points to the DSNINFO */
223  di = (DSNINFO *) lParam;
224  SetWindowUserData(hDlg, lParam);
225 
226  /* Stuff legal protocol names into IDC_PROTOCOL */
227  for (i = 0; protocols[i]; i++) {
228  SendDlgItemMessage(hDlg, IDC_PROTOCOL, CB_ADDSTRING, 0, (LPARAM) protocols[i]);
229  }
230 
231  /* copy info from DSNINFO to the dialog */
232  SendDlgItemMessage(hDlg, IDC_DSNNAME, WM_SETTEXT, 0, (LPARAM) tds_dstr_cstr(&di->dsn));
233  sprintf(tmp, "TDS %d.%d", TDS_MAJOR(di->login), TDS_MINOR(di->login));
234  SendDlgItemMessage(hDlg, IDC_PROTOCOL, CB_SELECTSTRING, -1, (LPARAM) tmp);
235  SendDlgItemMessage(hDlg, IDC_ADDRESS, WM_SETTEXT, 0, (LPARAM) tds_dstr_cstr(&di->login->server_name));
236  sprintf(tmp, "%u", di->login->port);
237  SendDlgItemMessage(hDlg, IDC_PORT, WM_SETTEXT, 0, (LPARAM) tmp);
238  SendDlgItemMessage(hDlg, IDC_DATABASE, WM_SETTEXT, 0, (LPARAM) tds_dstr_cstr(&di->login->database));
239 
240  return TRUE;
241 
242  case WM_COMMAND:
243  /* Dialog's user data points to DSNINFO */
244  di = (DSNINFO *) GetWindowUserData(hDlg);
245 
246  /* The wParam indicates which button was pressed */
247  if (LOWORD(wParam) == IDCANCEL) {
248  EndDialog(hDlg, FALSE);
249  return TRUE;
250  } else if (LOWORD(wParam) != IDOK) {
251  /* Anything but IDCANCEL or IDOK is handled elsewhere */
252  break;
253  }
254  /* If we get here, then the user hit the [OK] button */
255 
256  /* get values from dialog */
257  SendDlgItemMessage(hDlg, IDC_DSNNAME, WM_GETTEXT, sizeof tmp, (LPARAM) tmp);
258  tds_dstr_copy(&di->dsn, tmp);
259  SendDlgItemMessage(hDlg, IDC_PROTOCOL, WM_GETTEXT, sizeof tmp, (LPARAM) tmp);
260  minor = 0;
261  if (sscanf(tmp, "%*[^0-9]%d.%d", &major, &minor) > 1) {
262  if (major == 8 && minor == 0) {
263  major = 7;
264  minor = 1;
265  }
266  di->login->tds_version = (major << 8) | minor;
267  }
268  SendDlgItemMessage(hDlg, IDC_ADDRESS, WM_GETTEXT, sizeof tmp, (LPARAM) tmp);
270  SendDlgItemMessage(hDlg, IDC_PORT, WM_GETTEXT, sizeof tmp, (LPARAM) tmp);
271  di->login->port = atoi(tmp);
272  SendDlgItemMessage(hDlg, IDC_DATABASE, WM_GETTEXT, sizeof tmp, (LPARAM) tmp);
274 
275  /* validate */
276  SendDlgItemMessage(hDlg, IDC_HINT, WM_SETTEXT, 0, (LPARAM) "VALIDATING... please be patient");
277  pstr = validate(di);
278  if (pstr != NULL) {
279  SendDlgItemMessage(hDlg, IDC_HINT, WM_SETTEXT, 0, (LPARAM) pstr);
280  return TRUE;
281  }
282  SendDlgItemMessage(hDlg, IDC_HINT, WM_SETTEXT, 0, (LPARAM) "");
283 
284  /* No problems -- we're done */
285  EndDialog(hDlg, TRUE);
286  return TRUE;
287  }
288  return FALSE;
289 }
290 
291 
292 /**
293  * Add, remove, or modify a data source
294  * \param hwndParent parent for dialog, NULL for batch ops
295  * \param fRequest request type
296  * \param lpszDriver driver name (for humans, not DLL name)
297  * \param lpszAttributes attribute list
298  */
300 ConfigDSN(HWND hwndParent, WORD fRequest, LPCSTR lpszDriver, LPCSTR lpszAttributes)
301 {
302  INT_PTR result;
303  DSNINFO *di;
304  const char *errmsg;
305 
306  /*
307  * Initialize Windows sockets. This is necessary even though
308  * ConfigDSN() only looks up addresses and names, and never actually
309  * uses any sockets.
310  */
311  INITSOCKET();
312 
313  /* Create a blank login struct */
314  di = alloc_dsninfo();
315 
316  /*
317  * Parse the attribute string. If this contains a DSN name, then it
318  * also reads the current parameters of that DSN.
319  */
320  parse_wacky_dsn_string(lpszAttributes, di);
321 
322  /* Maybe allow the user to edit it */
323  if (hwndParent && fRequest != ODBC_REMOVE_DSN) {
324  result = DialogBoxParam(hinstFreeTDS, MAKEINTRESOURCE(IDD_DSN), hwndParent, (DLGPROC) DSNDlgProc, (LPARAM) di);
325  if (result < 0) {
326  DWORD errorcode = GetLastError();
327  char buf[1000];
328 
329  FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
330  errorcode, 0, buf, 1000, NULL);
331  }
332 
333  /* if user hit [Cancel] then clean up and return FALSE */
334  if (result == 0) {
335  goto Fail;
336  }
337  }
338 
339  switch (fRequest) {
340  case ODBC_ADD_DSN:
341  errmsg = validate(di);
342  if (errmsg != NULL) {
344  goto Fail;
345  }
346  if (!SQLWriteDSNToIni(tds_dstr_cstr(&di->dsn), lpszDriver)) {
347  goto Fail;
348  }
349  if (!write_all_strings(di)) {
350  goto Fail;
351  }
352  break;
353  case ODBC_CONFIG_DSN:
354  errmsg = validate(di);
355  if (errmsg != NULL) {
357  goto Fail;
358  }
359 
360  /*
361  * if the DSN name has changed, then delete the old entry and
362  * add the new one.
363  */
364  if (strcasecmp(tds_dstr_cstr(&di->origdsn), tds_dstr_cstr(&di->dsn))) {
366  || !SQLWriteDSNToIni(tds_dstr_cstr(&di->dsn), lpszDriver)) {
367  goto Fail;
368  }
369  }
370  if (!write_all_strings(di)) {
371  goto Fail;
372  }
373  break;
374  case ODBC_REMOVE_DSN:
375  if (!SQLRemoveDSNFromIni(tds_dstr_cstr(&di->dsn))) {
376  goto Fail;
377  }
378  break;
379  }
380 
381  /* Clean up and return TRUE, indicating that the change took place */
382  free_dsninfo(di);
383  DONESOCKET();
384  return TRUE;
385 
386  Fail:
387  free_dsninfo(di);
388  DONESOCKET();
389  return FALSE;
390 }
391 
392 /** Add or remove an ODBC driver */
394 ConfigDriver(HWND hwndParent, WORD fRequest, LPCSTR lpszDriver, LPCSTR lpszArgs, LPSTR lpszMsg, WORD cbMsgMax, WORD * pcbMsgOut)
395 {
396  const char *msg = NULL;
397 
398  /* TODO finish ?? */
399  switch (fRequest) {
400  case ODBC_INSTALL_DRIVER:
401  msg = "Hello";
402  break;
403  case ODBC_REMOVE_DRIVER:
404  msg = "Goodbye";
405  break;
406  }
407 
408  if (msg && lpszMsg && cbMsgMax > strlen(msg)) {
409  strcpy(lpszMsg, msg);
410  *pcbMsgOut = (WORD) strlen(msg);
411  }
412  return TRUE;
413 }
414 
416 ConfigTranslator(HWND hwndParent, DWORD * pvOption)
417 {
418  return TRUE;
419 }
420 
421 /**
422  * Allow install using regsvr32
423  */
424 HRESULT WINAPI
426 {
427  char fn[MAX_PATH], full_fn[MAX_PATH];
428  char *name;
429  WORD len_out;
430  DWORD cnt;
431  char *desc = NULL;
432  BOOL b_res;
433 
434  if ( !GetModuleFileNameA(hinstFreeTDS, fn, TDS_VECTOR_SIZE(fn)) )
435  return SELFREG_E_CLASS;
436  if ( !GetFullPathNameA(fn, TDS_VECTOR_SIZE(full_fn), full_fn, &name)
437  || !name || full_fn == name)
438  return SELFREG_E_CLASS;
439 
440  if (asprintf(&desc, "FreeTDS%c"
441  "APILevel=2%c"
442  "ConnectFunctions=YYN%c"
443  "DriverODBCVer=03.00%c"
444  "FileUsage=0%c"
445  "SQLLevel=2%c"
446  "Setup=%s%c"
447  "Driver=%s%c",
448  0, 0, 0, 0, 0, 0,
449  name, 0, name, 0
450  ) < 0)
451  return SELFREG_E_CLASS;
452  name[-1] = 0;
453 
454  b_res = SQLInstallDriverEx(desc, full_fn, fn, TDS_VECTOR_SIZE(fn), &len_out, ODBC_INSTALL_COMPLETE, &cnt);
455  free(desc);
456  if (!b_res)
457  return SELFREG_E_CLASS;
458  return S_OK;
459 }
460 
461 /**
462  * Allow uninstall using regsvr32 command
463  */
464 HRESULT WINAPI
466 {
467  DWORD cnt;
468  if (!SQLRemoveDriver("FreeTDS", FALSE, &cnt))
469  return SELFREG_E_CLASS;
470  return S_OK;
471 }
472 
#define strcat(s, k)
int odbc_parse_connect_string(TDS_ERRS *errs, const char *connect_string, const char *connect_string_end, TDSLOGIN *login, TDS_PARSED_PARAM *parsed_params)
Parses a connection string for SQLDriverConnect().
#define INITSOCKET()
#define DONESOCKET()
#define IS_TDS42(x)
Definition: tds.h:1699
#define TDS_MINOR(x)
Definition: tds.h:1715
#define IS_TDS50(x)
Definition: tds.h:1701
#define TDS_MAJOR(x)
Definition: tds.h:1714
#define TDS_VECTOR_SIZE(x)
Definition: tds.h:360
#define IS_TDS7_PLUS(x)
Definition: tds.h:1708
#define IS_TDS46(x)
Definition: tds.h:1700
#define IDC_PROTOCOL
Definition: resource.h:7
#define IDC_DSNNAME
Definition: resource.h:11
#define IDD_DSN
Definition: resource.h:6
#define IDC_PORT
Definition: resource.h:9
#define IDC_DATABASE
Definition: resource.h:10
#define IDC_HINT
Definition: resource.h:12
#define IDC_ADDRESS
Definition: resource.h:8
static const char * str(char *buf, int n)
Definition: stats.c:84
static char tmp[3200]
Definition: utf8.c:42
static BOOL write_all_strings(DSNINFO *di)
Definition: winsetup.c:145
#define FIELD_STRING(f)
Definition: winsetup.c:143
HRESULT WINAPI DllRegisterServer(void)
Allow install using regsvr32.
Definition: winsetup.c:425
static DSNINFO * alloc_dsninfo(void)
Create an empty DSNINFO struct.
Definition: winsetup.c:75
static void free_dsninfo(DSNINFO *di)
Destroy a DSNINFO struct, freeing all memory associated with it.
Definition: winsetup.c:92
static void parse_wacky_dsn_string(LPCSTR attribs, DSNINFO *di)
Parse a DSN string which is delimited with NULs instead of semicolons.
Definition: winsetup.c:109
#define SetWindowUserData(wnd, data)
Definition: winsetup.c:195
HRESULT WINAPI DllUnregisterServer(void)
Allow uninstall using regsvr32 command.
Definition: winsetup.c:465
#define WRITESTR(n, s)
Update the attributes.
Definition: winsetup.c:142
static BOOL CALLBACK DSNDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
Callback function for the DSN Configuration dialog.
Definition: winsetup.c:209
BOOL INSTAPI ConfigTranslator(HWND hwndParent, DWORD *pvOption)
Definition: winsetup.c:416
#define GetWindowUserData(wnd)
Definition: winsetup.c:194
BOOL INSTAPI ConfigDriver(HWND hwndParent, WORD fRequest, LPCSTR lpszDriver, LPCSTR lpszArgs, LPSTR lpszMsg, WORD cbMsgMax, WORD *pcbMsgOut)
Add or remove an ODBC driver.
Definition: winsetup.c:394
BOOL INSTAPI ConfigDSN(HWND hwndParent, WORD fRequest, LPCSTR lpszDriver, LPCSTR lpszAttributes)
Add, remove, or modify a data source.
Definition: winsetup.c:300
static const char * validate(DSNINFO *di)
Go looking for trouble.
Definition: winsetup.c:179
HINSTANCE hinstFreeTDS
Definition: initnet.c:10
#define asprintf
Definition: replacements.h:54
char * LPSTR
Definition: sqlfront.h:34
const char * LPCSTR
Definition: sqlfront.h:39
int BOOL
Definition: sybdb.h:150
#define tds_free_login
#define tds_init_login
#define tds_alloc_login
#define NULL
Definition: ncbistd.hpp:225
#define FILENAME_MAX
Definition: ncbifile.hpp:94
static const char * tds_dstr_cstr(DSTR *s)
Returns a C version (NUL terminated string) of dstr.
Definition: string.h:66
static void tds_dstr_init(DSTR *s)
init a string with empty
Definition: string.h:41
void tds_dstr_free(DSTR *s)
free string
Definition: tdsstring.c:63
DSTR * tds_dstr_copy(DSTR *s, const char *src) TDS_WUR
copy a string from another
Definition: tdsstring.c:123
static int tds_dstr_isempty(DSTR *s)
test if string is empty
Definition: string.h:48
use only n Cassandra database for the lookups</td > n</tr > n< tr > n< td > yes</td > n< td > do not use tables BIOSEQ_INFO and BLOB_PROP in the Cassandra database
char * buf
int i
#define strncasecmp
#define strcasecmp
#define TRUE
bool replacment for C indicating true.
Definition: ncbi_std.h:97
#define FALSE
bool replacment for C indicating false.
Definition: ncbi_std.h:101
static unsigned cnt[256]
#define ODBC_INSTALL_COMPLETE
Definition: odbcinst.h:105
#define ODBC_REMOVE_DRIVER
Definition: odbcinst.h:109
#define ODBC_ERROR_REQUEST_FAILED
Definition: odbcinst.h:133
int SQLWriteDSNToIni(LPCSTR lpszDSN, LPCSTR lpszDriver)
#define INSTAPI
Definition: odbcinst.h:154
SQLRETURN SQLPostInstallerError(DWORD dwErrorCode, LPCSTR lpszErrMsg)
int SQLRemoveDriver(LPCSTR lpszDriver, int fRemoveDSN, LPDWORD lpdwUsageCount)
int SQLValidDSN(LPCSTR lpszDSN)
#define ODBC_ADD_DSN
Definition: odbcinst.h:91
#define ODBC_REMOVE_DSN
Definition: odbcinst.h:93
int SQLInstallDriverEx(LPCSTR lpszDriver, LPCSTR lpszPathIn, LPSTR lpszPathOut, WORD cbPathOutMax, WORD *pcbPathOut, WORD fRequest, LPDWORD lpdwUsageCount)
int SQLRemoveDSNFromIni(LPCSTR lpszDSN)
#define ODBC_CONFIG_DSN
Definition: odbcinst.h:92
#define ODBC_INSTALL_DRIVER
Definition: odbcinst.h:108
unsigned short WORD
Definition: sqltypes.h:94
unsigned int UINT
Definition: sqltypes.h:263
void * HWND
Definition: sqltypes.h:73
unsigned int DWORD
Definition: sqltypes.h:98
#define CALLBACK
Definition: sqltypes.h:65
void * HINSTANCE
Definition: sqltypes.h:116
TDSLOGIN * login
everything else
Definition: winsetup.c:66
DSTR origdsn
original name of the data source
Definition: winsetup.c:64
DSTR dsn
edited name of the data source
Definition: winsetup.c:65
Structure to hold a string.
Definition: tds.h:116
Definition: tds.h:584
DSTR database
Definition: tds.h:611
DSTR server_name
server name (in freetds.conf)
Definition: tds.h:585
TDS_USMALLINT tds_version
TDS version.
Definition: tds.h:587
int text_size
Definition: tds.h:618
int port
port of database service
Definition: tds.h:586
int block_size
Definition: tds.h:588
else result
Definition: token2.c:20
void free(voidpf ptr)
voidp malloc(uInt size)
Modified on Wed Jul 24 17:15:41 2024 by modify_doxy.py rev. 669887