/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000-2004 Brian Bruns * * portions based on FreeTDS, Copyright (C) 1998-1999 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include "connectparams.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif /* * * Last resort place to check for INI file. This is usually set at compile time * * by build scripts. * */ #ifndef SYS_ODBC_INI #define SYS_ODBC_INI "/etc/odbc.ini" #endif #if defined(FILENAME_MAX) && FILENAME_MAX < 512 #undef FILENAME_MAX #define FILENAME_MAX 512 #endif #define max_line 256 static char line[max_line]; static guint HashFunction (gconstpointer key); #if !HAVE_SQLGETPRIVATEPROFILESTRING static GString* GetIniFileName (); static int FileExists (const gchar* name); static int FindSection (FILE* stream, const char* section); static int GetNextItem (FILE* stream, char** name, char** value); #endif //!HAVE_SQLGETPRIVATEPROFILESTRING static void visit (gpointer key, gpointer value, gpointer user_data); static gboolean cleanup (gpointer key, gpointer value, gpointer user_data); /* * Allocate create a ConnectParams object */ ConnectParams* NewConnectParams () { ConnectParams* params = (ConnectParams *) g_malloc(sizeof (ConnectParams)); if (!params) return params; params->dsnName = g_string_new (""); params->iniFileName = NULL; params->table = g_hash_table_new (HashFunction, g_str_equal); return params; } /* * Destroy a ConnectParams object */ void FreeConnectParams (ConnectParams* params) { if (params) { if (params->dsnName) g_string_free (params->dsnName, TRUE); if (params->iniFileName) g_string_free (params->iniFileName, TRUE); if (params->table) { g_hash_table_foreach_remove (params->table, cleanup, NULL); g_hash_table_destroy (params->table); } g_free(params); } } #if !HAVE_SQLGETPRIVATEPROFILESTRING static int LoadDSN ( const gchar* iniFileName, const gchar* dsnName, GHashTable* table) { FILE* stream; gchar* name; gchar* value; if ((stream = fopen (iniFileName, "r" )) != NULL ) { if (!FindSection (stream, dsnName)) { g_printerr ("Couldn't find DSN %s in %s\n", dsnName, iniFileName); fclose (stream); return 0; } else { while (GetNextItem (stream, &name, &value)) { g_hash_table_insert (table, strdup (name), strdup (value)); } } fclose( stream ); } return 1; } /* * Find the settings for the specified ODBC DSN */ gboolean LookupDSN (ConnectParams* params, const gchar* dsnName) { if (!params) { fprintf(stderr,"LookupDSN: no parameters, returning FALSE\n"); return FALSE; } /* * Set the DSN name property */ /* params->dsnName = g_string_assign (params->dsnName, dsnName); */ /* * Search for the ODBC ini file */ if (!(params->iniFileName = GetIniFileName ())) { fprintf(stderr,"LookupDSN: GetIniFileName returned FALSE\n"); return FALSE; } if (!LoadDSN (params->iniFileName->str, dsnName, params->table)) { fprintf(stderr,"LookupDSN: LoadDSN returned FALSE\n"); return FALSE; } return TRUE; } /* * Get the value of a given ODBC Connection Parameter */ gchar* GetConnectParam (ConnectParams* params, const gchar* paramName) { if (!params || !params->table) return NULL; return g_hash_table_lookup (params->table, paramName); } #else gboolean LookupDSN (ConnectParams* params, const gchar* dsnName) { return TRUE; } gchar* GetConnectParam (ConnectParams* params, const gchar* paramName) { static char tmp[FILENAME_MAX]; /* use old servername */ tmp[0] = '\0'; if (SQLGetPrivateProfileString(params->dsnName->str, paramName, "", tmp, FILENAME_MAX, "odbc.ini") > 0) { return tmp; } return NULL; } #endif /* !HAVE_SQLGETPRIVATEPROFILESTRING */ /* * Apply a connection string to the ODBC Parameter Settings */ void SetConnectString (ConnectParams* params, const gchar* connectString) { int end; char *cs, *s, *p, *name, *value; gpointer key; gpointer oldvalue; if (!params) return; /* * Make a copy of the connection string so we can modify it */ cs = (char *) g_strdup(connectString); s = cs; /* * Loop over ';' seperated name=value pairs */ p = strchr (s, '='); while (p) { if (p) *p = '\0'; /* * Extract name */ name = s; if (p) s = p + 1; /* * Extract value */ p = strchr (s, ';'); if (p) *p = '\0'; value = s; if (p) s = p + 1; /* * remove trailing spaces from name */ end = strlen (name) - 1; while (end > 0 && isspace(name[end])) name[end--] = '\0'; /* * remove leading spaces from value */ while (isspace(*value)) value++; if (g_hash_table_lookup_extended (params->table, name, &key, &oldvalue)) { /* * remove previous value */ g_hash_table_remove (params->table, key); /* * cleanup strings */ g_free (key); g_free (oldvalue); } /* * Insert the name/value pair into the hash table. * * Note that these g_strdup allocations are freed in cleanup, * which is called by FreeConnectParams. */ g_hash_table_insert (params->table, g_strdup (name), g_strdup (value)); p = strchr (s, '='); } g_free (cs); } /* * Dump all the ODBC Connection Paramters to a file (e.g. stdout) */ void DumpParams (ConnectParams* params, FILE* output) { if (!params) { g_printerr ("NULL ConnectionParams pointer\n"); return; } if (params->dsnName) g_printerr ("Parameter values for DSN: %s\n", params->dsnName->str); if (params->iniFileName) g_printerr ("Ini File is %s\n", params->iniFileName->str); g_hash_table_foreach (params->table, visit, output); } /* * Return the value of the DSN from the conneciton string */ gchar* ExtractDSN (ConnectParams* params, const gchar* connectString) { char *p, *q, *s; if (!params) return NULL; /* * Position ourselves to the beginning of "DSN" */ p = strstr (connectString, "DSN"); if (!p) return NULL; /* * Position ourselves to the "=" */ q = strchr (p, '='); if (!q) return NULL; /* * Skip over any leading spaces */ q++; while (isspace(*q)) q++; /* * Copy the DSN value to a buffer */ s = line; while (*q && *q != ';') *s++ = *q++; *s = '\0'; /* * Save it as a string in the params object */ params->dsnName = g_string_assign (params->dsnName, line); return params->dsnName->str; } gchar* ExtractDBQ (ConnectParams* params, const gchar* connectString) { char *p, *q, *s; if (!params) return NULL; /* * Position ourselves to the beginning of "DSN" */ p = strstr (connectString, "DBQ"); if (!p) return NULL; /* * Position ourselves to the "=" */ q = strchr (p, '='); if (!q) return NULL; /* * Skip over any leading spaces */ q++; while (isspace(*q)) q++; /* * Copy the DSN value to a buffer */ s = line; while (*q && *q != ';') *s++ = *q++; *s = '\0'; /* * Save it as a string in the params object */ params->dsnName = g_string_assign (params->dsnName, line); return params->dsnName->str; } /* * Begin local function definitions */ /* * Make a hash from all the characters */ static guint HashFunction (gconstpointer key) { guint value = 0; const char* s = key; while (*s) value += *s++; return value; } #if !HAVE_SQLGETPRIVATEPROFILESTRING static GString* GetIniFileName () { char* setting; GString* iniFileName = g_string_new (""); /* * First, try the ODBCINI environment variable */ if ((setting = getenv ("ODBCINI")) != NULL) { g_string_assign (iniFileName, getenv ("ODBCINI")); if (FileExists (iniFileName->str)) return iniFileName; g_string_assign (iniFileName, ""); } /* * Second, try the HOME environment variable */ if ((setting = getenv ("HOME")) != NULL) { g_string_assign (iniFileName, setting); iniFileName = g_string_append (iniFileName, "/.odbc.ini"); if (FileExists (iniFileName->str)) return iniFileName; g_string_assign (iniFileName, ""); } /* * As a last resort, try SYS_ODBC_INI */ g_string_assign (iniFileName, SYS_ODBC_INI); if (FileExists (iniFileName->str)) return iniFileName; g_string_assign (iniFileName, ""); return iniFileName; } static int FileExists (const gchar* name) { struct stat fileStat; return (stat (name, &fileStat) == 0); } static int FindSection (FILE* stream, const char* section) { char* s; char sectionPattern[max_line]; int len; strcpy (sectionPattern, "["); strcat (sectionPattern, section); strcat (sectionPattern, "]"); s = fgets (line, max_line, stream); while (s != NULL) { /* * Get rid of the newline character */ len = strlen (line); if (len > 0) line[strlen (line) - 1] = '\0'; /* * look for the section header */ if (strcmp (line, sectionPattern) == 0) return 1; s = fgets (line, max_line, stream); } return 0; } static int GetNextItem (FILE* stream, char** name, char** value) { char* s; int len; char equals[] = "="; /* used for seperator for strtok */ char* token; if (name == NULL || value == NULL) { g_printerr ("GetNextItem, invalid parameters"); return 0; } s = fgets (line, max_line, stream); if (s == NULL) { //perror ("fgets"); return 0; } /* * Get rid of the newline character */ len = strlen (line); if (len > 0) line[strlen (line) - 1] = '\0'; /* * Extract name from name = value */ if ((token = strtok (line, equals)) == NULL) return 0; len = strlen (token); while (len > 0 && isspace(token[len-1])) { len--; token[len] = '\0'; } *name = token; /* * extract value from name = value */ token = strtok (NULL, equals); if (token == NULL) return 0; while (*token && isspace(token[0])) token++; *value = token; return 1; } #endif //!HAVE_SQLGETPRIVATEPROFILESTRING static void visit (gpointer key, gpointer value, gpointer user_data) { FILE* output = (FILE*) user_data; fprintf(output, "Parameter: %s, Value: %s\n", (char*)key, (char*)value); } static gboolean cleanup (gpointer key, gpointer value, gpointer user_data) { g_free (key); g_free (value); return TRUE; } #ifdef UNIXODBC /* * Begin BIG Hack. * * We need these from odbcinstext.h but it wants to * include and , which are not in the * standard include path. XXX smurph * confirmed by unixODBC stuff, odbcinstext.h shouldn't be installed. freddy77 */ #define INI_MAX_LINE 1000 #define INI_MAX_OBJECT_NAME INI_MAX_LINE #define INI_MAX_PROPERTY_NAME INI_MAX_LINE #define INI_MAX_PROPERTY_VALUE INI_MAX_LINE #define ODBCINST_PROMPTTYPE_LABEL 0 /* readonly */ #define ODBCINST_PROMPTTYPE_TEXTEDIT 1 #define ODBCINST_PROMPTTYPE_LISTBOX 2 #define ODBCINST_PROMPTTYPE_COMBOBOX 3 #define ODBCINST_PROMPTTYPE_FILENAME 4 #define ODBCINST_PROMPTTYPE_HIDDEN 5 #define ODBCINST_PROMPTTYPE_TEXTEDIT_PASSWORD 6 typedef struct tODBCINSTPROPERTY { struct tODBCINSTPROPERTY *pNext; /* pointer to next property, NULL if last property */ char szName[INI_MAX_PROPERTY_NAME + 1]; /* property name */ char szValue[INI_MAX_PROPERTY_VALUE + 1]; /* property value */ int nPromptType; /* PROMPTTYPE_TEXTEDIT, PROMPTTYPE_LISTBOX, PROMPTTYPE_COMBOBOX, PROMPTTYPE_FILENAME */ char **aPromptData; /* array of pointers terminated with a NULL value in array. */ char *pszHelp; /* help on this property (driver setups should keep it short) */ void *pWidget; /* CALLER CAN STORE A POINTER TO ? HERE */ int bRefresh; /* app should refresh widget ie Driver Setup has changed aPromptData or szValue */ void *hDLL; /* for odbcinst internal use... only first property has valid one */ } ODBCINSTPROPERTY, *HODBCINSTPROPERTY; /* * End BIG Hack. */ int ODBCINSTGetProperties(HODBCINSTPROPERTY hLastProperty) { hLastProperty->pNext = (HODBCINSTPROPERTY) malloc(sizeof(ODBCINSTPROPERTY)); hLastProperty = hLastProperty->pNext; memset(hLastProperty, 0, sizeof(ODBCINSTPROPERTY)); hLastProperty->nPromptType = ODBCINST_PROMPTTYPE_FILENAME; strncpy(hLastProperty->szName, "Database", INI_MAX_PROPERTY_NAME); strncpy(hLastProperty->szValue, "", INI_MAX_PROPERTY_VALUE); hLastProperty->pszHelp = (char *) strdup("Filename and Path of MDB file to connect to.\n" "Use the full path to the database file."); return 1; } #endif