1 /** \file
2  *
3  * \author Copyright 2000 Scott Fritzinger
4  *
5  * \par License
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * \par
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * \par
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA  02110-1301  USA
22  */
23 
24 #define _DEFAULT_SOURCE
25 
26 #include "config.h"
27 #include <gphoto2/gphoto2-setting.h>
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include <gphoto2/gphoto2-result.h>
34 #include <gphoto2/gphoto2-port-log.h>
35 #include <gphoto2/gphoto2-port-portability.h>
36 
37 #ifdef WIN32
38 /* Win32 headers may use interface as a define; temporarily correct this */
39 #define interface struct
40 #include <Shlobj.h>
41 #undef interface
42 #endif
43 
44 /**
45  * Internal struct to store settings.
46  */
47 typedef struct {
48 	/* key = value settings */
49 	char id[256];
50 	char key[256];
51 	char value[256];
52 } Setting;
53 
54 /* Currently loaded settings */
55 static int             glob_setting_count = 0;
56 static Setting         glob_setting[512];
57 
58 static int save_settings (void);
59 
60 #define CHECK_RESULT(result)       {int r = (result); if (r < 0) return (r);}
61 
62 static int load_settings (void);
63 
64 /**
65  * \brief Retrieve a specific gphoto setting.
66  * \param id the frontend id of the caller
67  * \param key the key the frontend queries
68  * \param value changed value
69  * \return GPhoto error code
70  *
71  * This function retrieves the setting key for a specific frontend
72  * id and copies the value into the passed value pointer.
73  */
74 int
gp_setting_get(char * id,char * key,char * value)75 gp_setting_get (char *id, char *key, char *value)
76 {
77         int x;
78 
79 	C_PARAMS (id && key);
80 
81 	if (!glob_setting_count)
82 		load_settings ();
83 
84         for (x=0; x<glob_setting_count; x++) {
85                 if ((strcmp(glob_setting[x].id, id)==0) &&
86 		    (strcmp(glob_setting[x].key, key)==0)) {
87                         strcpy(value, glob_setting[x].value);
88                         return (GP_OK);
89                 }
90         }
91         strcpy(value, "");
92         return(GP_ERROR);
93 }
94 
95 /**
96  * \brief Set a specific gphoto setting.
97  *
98  * \param id the frontend id of the caller
99  * \param key the key the frontend queries
100  * \param value new value
101  * \return GPhoto error code
102  *
103  * This function sets the setting key for a specific frontend
104  * id to the value.
105  */
106 int
gp_setting_set(char * id,char * key,char * value)107 gp_setting_set (char *id, char *key, char *value)
108 {
109         int x;
110 
111 	C_PARAMS (id && key);
112 
113 	if (!glob_setting_count)
114 		load_settings ();
115 
116 	GP_LOG_D ("Setting key '%s' to value '%s' (%s)", key, value, id);
117 
118         for (x=0; x<glob_setting_count; x++) {
119                 if ((strcmp(glob_setting[x].id, id)==0) &&
120 		    (strcmp(glob_setting[x].key, key)==0)) {
121                         strcpy(glob_setting[x].value, value);
122                         save_settings ();
123                         return (GP_OK);
124                 }
125 	}
126         strcpy(glob_setting[glob_setting_count].id, id);
127         strcpy(glob_setting[glob_setting_count].key, key);
128         strcpy(glob_setting[glob_setting_count++].value, value);
129         save_settings ();
130 
131         return (GP_OK);
132 }
133 
134 static int
verify_settings(char * settings_file)135 verify_settings (char *settings_file)
136 {
137 	FILE *f;
138 	char buf[1024];
139 	unsigned int x, equals;
140 
141 	if ((f=fopen(settings_file, "r"))==NULL) {
142 		GP_LOG_D ("Can't open settings file '%s' for reading.", settings_file);
143 		return(0);
144 	}
145 
146 	rewind(f);
147 	while (!feof(f)) {
148 		strcpy(buf, "");
149 		if (!fgets(buf, 1023, f))
150 			break;
151 		buf[strlen(buf)] = 0;
152 		if (strlen(buf)>2) {
153 			equals = 0;
154 			for (x=0; x<strlen(buf); x++)
155 				if (buf[x] == '=')
156 					equals++;
157 
158 			if (equals < 2) {
159 				fclose (f);
160 				GP_LOG_E ("Incorrect settings format. Resetting.");
161 				unlink(settings_file);
162 				return (GP_ERROR);
163 			}
164 		}
165 	}
166 	fclose (f);
167 
168 	return (GP_OK);
169 }
170 
171 static int
load_settings(void)172 load_settings (void)
173 {
174 	FILE *f;
175 	char buf[1024], *id, *key, *value;
176 
177 	/* Make sure the directories are created */
178 #ifdef WIN32
179 	SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, buf);
180 	strcat (buf, "\\.gphoto");
181 #else
182 	snprintf (buf, sizeof(buf), "%s/.gphoto", getenv ("HOME"));
183 #endif
184 	GP_LOG_D ("Creating gphoto config directory ('%s')", buf);
185 	(void)gp_system_mkdir (buf);
186 
187 	glob_setting_count = 0;
188 #ifdef WIN32
189 	SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, buf);
190 	strcat(buf, "\\.gphoto\\settings");
191 #else
192 	snprintf(buf, sizeof(buf), "%s/.gphoto/settings", getenv("HOME"));
193 #endif
194 
195 	if (verify_settings(buf) != GP_OK)
196 		/* verify_settings will unlink and recreate the settings file */
197 		return (GP_OK);
198 	GP_LOG_D ("Loading settings from file '%s'.", buf);
199 
200 	if ((f=fopen(buf, "r"))==NULL) {
201 		GP_LOG_D ("Can't open settings file '%s' for reading.", buf);
202 		return(GP_ERROR);
203 	}
204 
205 	rewind(f);
206 	while (!feof(f)) {
207 		strcpy(buf, "");
208 		if (!fgets(buf, 1023, f))
209 			break;
210 		if (strlen(buf)>2) {
211 		     buf[strlen(buf)-1] = '\0';
212 		     id = strtok(buf, "=");
213 		     strcpy(glob_setting[glob_setting_count].id,id);
214 		     key = strtok(NULL, "=");
215 		     strcpy(glob_setting[glob_setting_count].key,key);
216 		     value = strtok(NULL, "\0");
217 		     if (value)
218 			strcpy(glob_setting[glob_setting_count++].value, value);
219 		       else
220 			strcpy(glob_setting[glob_setting_count++].value, "");
221 		}
222 	}
223 	fclose (f);
224 	return (GP_OK);
225 }
226 
227 
228 static int
save_settings(void)229 save_settings (void)
230 {
231 	FILE *f;
232 	char buf[1024];
233 	int x=0;
234 
235 #ifdef WIN32
236 	SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, buf);
237 	strcat(buf, "\\.gphoto\\settings");
238 #else
239 	snprintf (buf, sizeof(buf), "%s/.gphoto/settings", getenv ("HOME"));
240 #endif
241 
242 
243 	GP_LOG_D ("Saving %i setting(s) to file \"%s\"", glob_setting_count, buf);
244 
245 	if ((f=fopen(buf, "w+"))==NULL) {
246 		GP_LOG_E ("Can't open settings file for writing.");
247 		return(0);
248 	}
249 	rewind(f);
250 	while (x < glob_setting_count) {
251 		fwrite(glob_setting[x].id, strlen(glob_setting[x].id),1,f);
252 		fputc('=', f);
253 		fwrite(glob_setting[x].key, strlen(glob_setting[x].key),1,f);
254 		fputc('=', f);
255 		fwrite(glob_setting[x].value, strlen(glob_setting[x].value),1,f);
256 		fputc('\n', f);
257 		x++;
258 	}
259 	fclose(f);
260 
261 	return (GP_OK);
262 }
263 
264 #if 0
265 static int dump_settings (void)
266 {
267 	int x;
268 
269 	gp_debug_printf(GP_DEBUG_LOW, "core", "All settings:");
270 	for (x=0; x<glob_setting_count; x++)
271 		gp_debug_printf(GP_DEBUG_LOW, "core", "\t (%s) \"%s\" = \"%s\"", glob_setting[x].id,
272 			glob_setting[x].key,glob_setting[x].value);
273 	if (glob_setting_count == 0)
274 		gp_debug_printf(GP_DEBUG_LOW, "core", "\tNone");
275 	gp_debug_printf(GP_DEBUG_LOW, "core", "Total settings: %i", glob_setting_count);
276 
277 	return (GP_OK);
278 }
279 #endif
280