Initial commit
[edesklets.git] / core / src / conf.c
blob1e9e2d0f467ef09c55e44e0d9468c068296977e4
1 /*-----------------------------------------------------------------------------
2 Copyright (C) Sylvain Fourmanoit <syfou@users.sourceforge.net>
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to
6 deal in the Software without restriction, including without limitation the
7 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 sell copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies of the Software and its documentation and acknowledgment shall be
13 given in the documentation and software packages that this Software was
14 used.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 ------------------------------------------------------------------------------*/
24 #include "edesklets.h"
26 #ifdef HAVE_STRING_H
27 #include <string.h> /* memcpy() */
28 #endif
30 /*---------------------------------------------------------------------------*/
31 const Desklet DESKLET_DEFAULTS = {
32 NULL, /* gchar * id; */
33 NULL, /* gchar * uri; */
34 0, 0, 300, 200, /* gint x, y, width, height; */
35 FALSE, /* gboolean decorate; */
36 5, 1 /* gint timeout, attempts; */
39 /*---------------------------------------------------------------------------*/
40 void
41 config_default(Desklet * desc) {
42 g_memmove(desc, &DESKLET_DEFAULTS, sizeof(Desklet));
45 /*---------------------------------------------------------------------------*/
46 gchar *
47 config_path(gchar * basename) {
48 gchar * path, * ret;
50 path = g_build_filename(g_get_user_config_dir(), PACKAGE_NAME, NULL);
51 if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
52 g_warning(_("trying to create configure dir '%s'"), path);
53 g_mkdir_with_parents(path, 0755);
55 ret = g_build_filename(path, basename, NULL);
56 g_free(path);
57 return ret;
60 /*---------------------------------------------------------------------------*/
61 static EConfig *
62 config_new(void) {
63 EConfig * conf;
64 if ((conf = g_malloc0(sizeof(EConfig))))
65 if (!(conf->desklets = g_array_new(FALSE, TRUE, sizeof(Desklet)))) {
66 g_free(conf);
67 conf = NULL;
69 return conf;
72 /*---------------------------------------------------------------------------*/
73 EConfig *
74 config_load(gboolean nolock, gboolean readonly) {
75 GError * err = NULL;
76 GIOChannel * gio;
77 gchar * fn, * buf, ** groups;
78 gint i;
79 gsize n;
80 Desklet desc;
81 EConfig * conf;
83 #define crash(...) \
84 do{\
85 conf->crashmode = TRUE;\
86 conf->crashmsg = g_strdup_printf(__VA_ARGS__);\
87 g_warning(conf->crashmsg);\
88 }while(0)
90 if ((conf = config_new())) {
91 conf->kf = g_key_file_new();
92 fn = config_path("config");
93 if ((conf->lf = fopen_locked(fn,
94 g_file_test(fn, G_FILE_TEST_EXISTS)?"r+":"w+",
95 !nolock, FALSE || readonly, &err))) {
96 gio = g_io_channel_unix_new(fileno(file(conf->lf)));
97 g_io_channel_read_to_end(gio, &buf, &n, NULL);
98 g_io_channel_unref(gio);
99 if (n>0) {
100 if (g_key_file_load_from_data(conf->kf, buf, n,
101 G_KEY_FILE_KEEP_COMMENTS,
102 &err)) {
103 groups = g_key_file_get_groups(conf->kf, &n);
104 for(i=0; i<n; ++i)
105 if (g_ascii_strcasecmp("general", groups[i])!=0) {
106 #define KEY_GET(param, type) \
107 do {\
108 g_clear_error(&err);\
109 desc.param = g_key_file_get_ ## type(conf->kf, groups[i], #param, &err);\
110 if (err) {\
111 g_clear_error(&err);\
112 g_warning(_("could not retrieve value for %s on %s"), #param, groups[i]);\
113 desc.param = DESKLET_DEFAULTS.param;\
115 } while(0)
116 KEY_GET(id, string);
117 KEY_GET(uri, string);
118 KEY_GET(x, integer);
119 KEY_GET(y, integer);
120 KEY_GET(width, integer);
121 KEY_GET(height, integer);
122 KEY_GET(decorate, boolean);
123 KEY_GET(timeout, integer);
124 KEY_GET(attempts, integer);
125 #undef KEY_GET
126 g_array_append_val(conf->desklets, desc);
128 g_strfreev(groups);
129 } else {
130 g_warning(err->message);
131 crash(_("Loading settings from '%s' skipped entirely "
132 "due to parsing error."), fn);
133 g_error_free(err);
135 } else
136 g_warning(_("config file has zero lenght (first use?)."));
138 g_free(buf);
139 } else {
140 if (err->code == EERROR_ALREADY_LOCKED) {
141 g_warning(_("could not get lock on '%s': %s"), fn, err->message);
142 crash(_("Could not lock config file: "
143 "you can only edit one desklet at a time. "
144 "If you are not already editing the config of another desklet, "
145 "this might mean locking is not supported by the local system: "
146 "look at eDesklets online FAQ."));
147 } else {
148 g_warning(err->message);
149 crash(_("Could not load config file: "
150 "look at eDesklets online FAQ."));
152 g_error_free(err);
154 g_free(fn);
155 if ((conf->crashmode = conf->crashmode || readonly)) {
156 if (conf->kf) g_key_file_free(conf->kf); conf->kf = NULL;
157 if (conf->lf) fclose_locked(&conf->lf, NULL);
159 } else
160 g_error(_("Could not allocate configuration"));
161 return conf;
163 #undef crash
166 /*---------------------------------------------------------------------------*/
167 gint
168 config_merge(EConfig * conf, Desklet * desc) {
169 gint i;
170 Desklet * item;
171 g_assert(desc->id);
172 for (i=0; i<conf->desklets->len; ++i) {
173 item = &g_array_index(conf->desklets, Desklet, i);
174 if (g_ascii_strcasecmp(desc->id, item->id)==0)
175 break;
177 if (i == conf->desklets->len)
178 g_array_append_val(conf->desklets, (*desc));
179 return i;
182 /*---------------------------------------------------------------------------*/
183 void
184 config_dump(EConfig ** conf) {
185 GTimeVal tv;
186 gchar * out, *group, **groups, *isotime, *comment;
187 Desklet * item;
188 gint i, j;
189 gsize n;
190 LFILE * fout;
192 if (!conf || !(*conf)) return;
193 if ((*conf)->crashmode)
194 goto end;
196 #define kf ((*conf)->kf)
198 /* ...top comment */
199 g_get_current_time(&tv);
200 isotime = g_time_val_to_iso8601(&tv);
201 comment = g_strdup_printf(_("\
202 Edit at your own risk! (last modified: %s)\n"), isotime);
203 g_key_file_set_comment(kf, NULL, NULL, comment, NULL);
204 g_free(comment);
205 g_free(isotime);
207 /* ...existing values */
208 for(i=0; i<(*conf)->desklets->len;++i) {
209 group = g_strdup_printf("desklet_%d", i);
210 item = &g_array_index((*conf)->desklets, Desklet, i);
211 if (item->id)
212 g_key_file_set_string (kf, group, "id" , item->id);
213 if (item->uri)
214 g_key_file_set_string (kf, group, "uri" , item->uri);
215 if (item->x >=0)
216 g_key_file_set_integer(kf, group, "x" , item->x);
217 if (item->y >=0)
218 g_key_file_set_integer(kf, group, "y" , item->y);
219 g_key_file_set_integer(kf, group, "width" , item->width);
220 g_key_file_set_integer(kf, group, "height" , item->height);
221 g_key_file_set_boolean(kf, group, "decorate", item->decorate);
222 g_key_file_set_integer(kf, group, "timeout" , item->timeout);
223 g_key_file_set_integer(kf, group, "attempts", item->attempts);
224 g_free(group);
227 /* ...strip removed values */
228 groups = g_key_file_get_groups(kf, &n);
229 for(i=0; i<n; ++i)
230 if ((g_ascii_strcasecmp("general", groups[i])!=0) &&
231 ((g_strstr_len(groups[i], 8, "desklet_")==NULL) ||
232 (atoi(groups[i]+8) >= (*conf)->desklets->len)))
233 g_key_file_remove_group(kf, groups[i], NULL);
235 /* Dump it to file */
236 out = g_key_file_to_data(kf, &n, NULL);
237 fseek(file((*conf)->lf), 0, SEEK_SET);
238 fwrite(out, n, 1, file((*conf)->lf));
239 ftruncate(fileno(file((*conf)->lf)), n);
240 g_free(out);
242 end:
243 fclose_locked(&(*conf)->lf, NULL);
244 if (kf) g_key_file_free(kf);
245 g_array_free((*conf)->desklets, TRUE);
246 if ((*conf)->crashmsg) g_free((*conf)->crashmsg);
247 g_free(*conf);
248 *conf = NULL;
250 #undef kf
253 /*---------------------------------------------------------------------------*/