Statistics
| Revision:

root / libsylph / prefs.c @ 1973

History | View | Annotate | Download (11 kB)

1 528 hiro
/*
2 578 hiro
 * LibSylph -- E-Mail client library
3 528 hiro
 * Copyright (C) 1999-2005 Hiroyuki Yamamoto
4 528 hiro
 *
5 578 hiro
 * This library is free software; you can redistribute it and/or
6 578 hiro
 * modify it under the terms of the GNU Lesser General Public
7 578 hiro
 * License as published by the Free Software Foundation; either
8 578 hiro
 * version 2.1 of the License, or (at your option) any later version.
9 528 hiro
 *
10 578 hiro
 * This library is distributed in the hope that it will be useful,
11 528 hiro
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 578 hiro
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 578 hiro
 * Lesser General Public License for more details.
14 528 hiro
 *
15 578 hiro
 * You should have received a copy of the GNU Lesser General Public
16 578 hiro
 * License along with this library; if not, write to the Free Software
17 578 hiro
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 528 hiro
 */
19 528 hiro
20 528 hiro
#ifdef HAVE_CONFIG_H
21 528 hiro
#  include "config.h"
22 528 hiro
#endif
23 528 hiro
24 528 hiro
#include <glib.h>
25 528 hiro
#include <glib/gi18n.h>
26 528 hiro
#include <stdio.h>
27 528 hiro
#include <stdlib.h>
28 528 hiro
#include <string.h>
29 528 hiro
#include <unistd.h>
30 528 hiro
#include <errno.h>
31 528 hiro
32 528 hiro
#include "prefs.h"
33 528 hiro
#include "codeconv.h"
34 528 hiro
#include "utils.h"
35 528 hiro
36 528 hiro
typedef enum
37 528 hiro
{
38 528 hiro
        DUMMY_PARAM
39 528 hiro
} DummyEnum;
40 528 hiro
41 530 hiro
static void prefs_config_parse_one_line        (GHashTable        *param_table,
42 530 hiro
                                         const gchar        *buf);
43 530 hiro
44 530 hiro
GHashTable *prefs_param_table_get(PrefParam *param)
45 530 hiro
{
46 530 hiro
        GHashTable *table;
47 530 hiro
        gint i;
48 530 hiro
49 530 hiro
        g_return_val_if_fail(param != NULL, NULL);
50 530 hiro
51 530 hiro
        table = g_hash_table_new(g_str_hash, g_str_equal);
52 530 hiro
53 530 hiro
        for (i = 0; param[i].name != NULL; i++) {
54 530 hiro
                g_hash_table_insert(table, param[i].name, &param[i]);
55 530 hiro
        }
56 530 hiro
57 530 hiro
        return table;
58 530 hiro
}
59 530 hiro
60 530 hiro
void prefs_param_table_destroy(GHashTable *param_table)
61 530 hiro
{
62 530 hiro
        g_hash_table_destroy(param_table);
63 530 hiro
}
64 530 hiro
65 528 hiro
void prefs_read_config(PrefParam *param, const gchar *label,
66 528 hiro
                       const gchar *rcfile, const gchar *encoding)
67 528 hiro
{
68 528 hiro
        FILE *fp;
69 528 hiro
        gchar buf[PREFSBUFSIZE];
70 528 hiro
        gchar *block_label;
71 530 hiro
        GHashTable *param_table;
72 528 hiro
73 528 hiro
        g_return_if_fail(param != NULL);
74 528 hiro
        g_return_if_fail(label != NULL);
75 528 hiro
        g_return_if_fail(rcfile != NULL);
76 528 hiro
77 528 hiro
        debug_print("Reading configuration...\n");
78 528 hiro
79 528 hiro
        prefs_set_default(param);
80 528 hiro
81 528 hiro
        if ((fp = g_fopen(rcfile, "rb")) == NULL) {
82 528 hiro
                if (ENOENT != errno) FILE_OP_ERROR(rcfile, "fopen");
83 528 hiro
                return;
84 528 hiro
        }
85 528 hiro
86 528 hiro
        block_label = g_strdup_printf("[%s]", label);
87 528 hiro
88 528 hiro
        /* search aiming block */
89 528 hiro
        while (fgets(buf, sizeof(buf), fp) != NULL) {
90 528 hiro
                gint val;
91 528 hiro
92 528 hiro
                if (encoding) {
93 528 hiro
                        gchar *conv_str;
94 528 hiro
95 528 hiro
                        conv_str = conv_codeset_strdup
96 528 hiro
                                (buf, encoding, CS_INTERNAL);
97 528 hiro
                        if (!conv_str)
98 528 hiro
                                conv_str = g_strdup(buf);
99 528 hiro
                        val = strncmp
100 528 hiro
                                (conv_str, block_label, strlen(block_label));
101 528 hiro
                        g_free(conv_str);
102 528 hiro
                } else
103 528 hiro
                        val = strncmp(buf, block_label, strlen(block_label));
104 528 hiro
                if (val == 0) {
105 528 hiro
                        debug_print("Found %s\n", block_label);
106 528 hiro
                        break;
107 528 hiro
                }
108 528 hiro
        }
109 528 hiro
        g_free(block_label);
110 528 hiro
111 530 hiro
        param_table = prefs_param_table_get(param);
112 530 hiro
113 528 hiro
        while (fgets(buf, sizeof(buf), fp) != NULL) {
114 528 hiro
                strretchomp(buf);
115 530 hiro
                if (buf[0] == '\0') continue;
116 528 hiro
                /* reached next block */
117 528 hiro
                if (buf[0] == '[') break;
118 528 hiro
119 528 hiro
                if (encoding) {
120 528 hiro
                        gchar *conv_str;
121 528 hiro
122 528 hiro
                        conv_str = conv_codeset_strdup
123 528 hiro
                                (buf, encoding, CS_INTERNAL);
124 528 hiro
                        if (!conv_str)
125 528 hiro
                                conv_str = g_strdup(buf);
126 530 hiro
                        prefs_config_parse_one_line(param_table, conv_str);
127 528 hiro
                        g_free(conv_str);
128 528 hiro
                } else
129 530 hiro
                        prefs_config_parse_one_line(param_table, buf);
130 528 hiro
        }
131 528 hiro
132 530 hiro
        prefs_param_table_destroy(param_table);
133 530 hiro
134 528 hiro
        debug_print("Finished reading configuration.\n");
135 528 hiro
        fclose(fp);
136 528 hiro
}
137 528 hiro
138 530 hiro
static void prefs_config_parse_one_line(GHashTable *param_table,
139 530 hiro
                                        const gchar *buf)
140 528 hiro
{
141 530 hiro
        PrefParam *param;
142 530 hiro
        const gchar *p = buf;
143 530 hiro
        gchar *name;
144 528 hiro
        const gchar *value;
145 528 hiro
146 530 hiro
        while (*p && *p != '=')
147 530 hiro
                p++;
148 528 hiro
149 530 hiro
        if (*p != '=') {
150 530 hiro
                g_warning("invalid pref line: %s\n", buf);
151 530 hiro
                return;
152 528 hiro
        }
153 530 hiro
154 530 hiro
        name = g_strndup(buf, p - buf);
155 530 hiro
        value = p + 1;
156 530 hiro
157 530 hiro
        /* debug_print("%s = %s\n", name, value); */
158 530 hiro
159 530 hiro
        param = g_hash_table_lookup(param_table, name);
160 530 hiro
161 530 hiro
        if (!param) {
162 530 hiro
                debug_print("pref key '%s' (value '%s') not found\n",
163 530 hiro
                            name, value);
164 530 hiro
                g_free(name);
165 530 hiro
                return;
166 530 hiro
        }
167 530 hiro
168 530 hiro
        switch (param->type) {
169 530 hiro
        case P_STRING:
170 530 hiro
                g_free(*((gchar **)param->data));
171 530 hiro
                *((gchar **)param->data) = *value ? g_strdup(value) : NULL;
172 530 hiro
                break;
173 530 hiro
        case P_INT:
174 530 hiro
                *((gint *)param->data) = (gint)atoi(value);
175 530 hiro
                break;
176 530 hiro
        case P_BOOL:
177 530 hiro
                *((gboolean *)param->data) =
178 530 hiro
                        (*value == '0' || *value == '\0') ? FALSE : TRUE;
179 530 hiro
                break;
180 530 hiro
        case P_ENUM:
181 530 hiro
                *((DummyEnum *)param->data) = (DummyEnum)atoi(value);
182 530 hiro
                break;
183 530 hiro
        case P_USHORT:
184 530 hiro
                *((gushort *)param->data) = (gushort)atoi(value);
185 530 hiro
                break;
186 530 hiro
        default:
187 530 hiro
                break;
188 530 hiro
        }
189 530 hiro
190 530 hiro
        g_free(name);
191 528 hiro
}
192 528 hiro
193 528 hiro
#define TRY(func) \
194 528 hiro
if (!(func)) \
195 528 hiro
{ \
196 528 hiro
        g_warning(_("failed to write configuration to file\n")); \
197 528 hiro
        if (orig_fp) fclose(orig_fp); \
198 528 hiro
        prefs_file_close_revert(pfile); \
199 528 hiro
        g_free(rcpath); \
200 528 hiro
        g_free(block_label); \
201 528 hiro
        return; \
202 528 hiro
} \
203 528 hiro
204 528 hiro
void prefs_write_config(PrefParam *param, const gchar *label,
205 528 hiro
                        const gchar *rcfile)
206 528 hiro
{
207 528 hiro
        FILE *orig_fp;
208 528 hiro
        PrefFile *pfile;
209 528 hiro
        gchar *rcpath;
210 528 hiro
        gchar buf[PREFSBUFSIZE];
211 528 hiro
        gchar *block_label = NULL;
212 528 hiro
        gboolean block_matched = FALSE;
213 528 hiro
214 528 hiro
        g_return_if_fail(param != NULL);
215 528 hiro
        g_return_if_fail(label != NULL);
216 528 hiro
        g_return_if_fail(rcfile != NULL);
217 528 hiro
218 528 hiro
        rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, rcfile, NULL);
219 528 hiro
        if ((orig_fp = g_fopen(rcpath, "rb")) == NULL) {
220 528 hiro
                if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
221 528 hiro
        }
222 528 hiro
223 528 hiro
        if ((pfile = prefs_file_open(rcpath)) == NULL) {
224 528 hiro
                g_warning(_("failed to write configuration to file\n"));
225 528 hiro
                if (orig_fp) fclose(orig_fp);
226 528 hiro
                g_free(rcpath);
227 528 hiro
                return;
228 528 hiro
        }
229 528 hiro
230 528 hiro
        block_label = g_strdup_printf("[%s]", label);
231 528 hiro
232 528 hiro
        /* search aiming block */
233 528 hiro
        if (orig_fp) {
234 528 hiro
                while (fgets(buf, sizeof(buf), orig_fp) != NULL) {
235 528 hiro
                        gint val;
236 528 hiro
237 528 hiro
                        val = strncmp(buf, block_label, strlen(block_label));
238 528 hiro
                        if (val == 0) {
239 528 hiro
                                debug_print(_("Found %s\n"), block_label);
240 528 hiro
                                block_matched = TRUE;
241 528 hiro
                                break;
242 528 hiro
                        } else
243 528 hiro
                                TRY(fputs(buf, pfile->fp) != EOF);
244 528 hiro
                }
245 528 hiro
        }
246 528 hiro
247 528 hiro
        TRY(fprintf(pfile->fp, "%s\n", block_label) > 0);
248 528 hiro
        g_free(block_label);
249 528 hiro
        block_label = NULL;
250 528 hiro
251 528 hiro
        /* write all param data to file */
252 528 hiro
        TRY(prefs_file_write_param(pfile, param) == 0);
253 528 hiro
254 528 hiro
        if (block_matched) {
255 528 hiro
                while (fgets(buf, sizeof(buf), orig_fp) != NULL) {
256 528 hiro
                        /* next block */
257 528 hiro
                        if (buf[0] == '[') {
258 528 hiro
                                TRY(fputc('\n', pfile->fp) != EOF &&
259 528 hiro
                                    fputs(buf, pfile->fp)  != EOF);
260 528 hiro
                                break;
261 528 hiro
                        }
262 528 hiro
                }
263 528 hiro
                while (fgets(buf, sizeof(buf), orig_fp) != NULL)
264 528 hiro
                        TRY(fputs(buf, pfile->fp) != EOF);
265 528 hiro
        }
266 528 hiro
267 528 hiro
        if (orig_fp) fclose(orig_fp);
268 528 hiro
        if (prefs_file_close(pfile) < 0)
269 528 hiro
                g_warning(_("failed to write configuration to file\n"));
270 528 hiro
        g_free(rcpath);
271 528 hiro
272 528 hiro
        debug_print(_("Configuration is saved.\n"));
273 528 hiro
}
274 528 hiro
275 528 hiro
gint prefs_file_write_param(PrefFile *pfile, PrefParam *param)
276 528 hiro
{
277 528 hiro
        gint i;
278 528 hiro
        gchar buf[PREFSBUFSIZE];
279 528 hiro
280 528 hiro
        for (i = 0; param[i].name != NULL; i++) {
281 528 hiro
                switch (param[i].type) {
282 528 hiro
                case P_STRING:
283 528 hiro
                        g_snprintf(buf, sizeof(buf), "%s=%s\n", param[i].name,
284 528 hiro
                                   *((gchar **)param[i].data) ?
285 528 hiro
                                   *((gchar **)param[i].data) : "");
286 528 hiro
                        break;
287 528 hiro
                case P_INT:
288 528 hiro
                        g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
289 528 hiro
                                   *((gint *)param[i].data));
290 528 hiro
                        break;
291 528 hiro
                case P_BOOL:
292 528 hiro
                        g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
293 528 hiro
                                   *((gboolean *)param[i].data));
294 528 hiro
                        break;
295 528 hiro
                case P_ENUM:
296 528 hiro
                        g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
297 528 hiro
                                   *((DummyEnum *)param[i].data));
298 528 hiro
                        break;
299 528 hiro
                case P_USHORT:
300 528 hiro
                        g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
301 528 hiro
                                   *((gushort *)param[i].data));
302 528 hiro
                        break;
303 528 hiro
                default:
304 528 hiro
                        buf[0] = '\0';
305 528 hiro
                }
306 528 hiro
307 528 hiro
                if (buf[0] != '\0') {
308 528 hiro
                        if (fputs(buf, pfile->fp) == EOF) {
309 528 hiro
                                perror("fputs");
310 528 hiro
                                return -1;
311 528 hiro
                        }
312 528 hiro
                }
313 528 hiro
        }
314 528 hiro
315 528 hiro
        return 0;
316 528 hiro
}
317 528 hiro
318 528 hiro
PrefFile *prefs_file_open(const gchar *path)
319 528 hiro
{
320 528 hiro
        PrefFile *pfile;
321 528 hiro
        gchar *tmppath;
322 528 hiro
        FILE *fp;
323 528 hiro
324 528 hiro
        g_return_val_if_fail(path != NULL, NULL);
325 528 hiro
326 528 hiro
        tmppath = g_strconcat(path, ".tmp", NULL);
327 528 hiro
        if ((fp = g_fopen(tmppath, "wb")) == NULL) {
328 528 hiro
                FILE_OP_ERROR(tmppath, "fopen");
329 528 hiro
                g_free(tmppath);
330 528 hiro
                return NULL;
331 528 hiro
        }
332 528 hiro
333 528 hiro
        if (change_file_mode_rw(fp, tmppath) < 0)
334 528 hiro
                FILE_OP_ERROR(tmppath, "chmod");
335 528 hiro
336 528 hiro
        g_free(tmppath);
337 528 hiro
338 528 hiro
        pfile = g_new(PrefFile, 1);
339 528 hiro
        pfile->fp = fp;
340 528 hiro
        pfile->path = g_strdup(path);
341 528 hiro
342 528 hiro
        return pfile;
343 528 hiro
}
344 528 hiro
345 528 hiro
gint prefs_file_close(PrefFile *pfile)
346 528 hiro
{
347 528 hiro
        FILE *fp;
348 528 hiro
        gchar *path;
349 528 hiro
        gchar *tmppath;
350 528 hiro
        gchar *bakpath = NULL;
351 528 hiro
352 528 hiro
        g_return_val_if_fail(pfile != NULL, -1);
353 528 hiro
354 528 hiro
        fp = pfile->fp;
355 528 hiro
        path = pfile->path;
356 528 hiro
        g_free(pfile);
357 528 hiro
358 528 hiro
        tmppath = g_strconcat(path, ".tmp", NULL);
359 528 hiro
        if (fclose(fp) == EOF) {
360 528 hiro
                FILE_OP_ERROR(tmppath, "fclose");
361 528 hiro
                g_unlink(tmppath);
362 528 hiro
                g_free(path);
363 528 hiro
                g_free(tmppath);
364 528 hiro
                return -1;
365 528 hiro
        }
366 528 hiro
367 528 hiro
        if (is_file_exist(path)) {
368 528 hiro
                bakpath = g_strconcat(path, ".bak", NULL);
369 528 hiro
                if (rename_force(path, bakpath) < 0) {
370 528 hiro
                        FILE_OP_ERROR(path, "rename");
371 528 hiro
                        g_unlink(tmppath);
372 528 hiro
                        g_free(path);
373 528 hiro
                        g_free(tmppath);
374 528 hiro
                        g_free(bakpath);
375 528 hiro
                        return -1;
376 528 hiro
                }
377 528 hiro
        }
378 528 hiro
379 528 hiro
        if (rename_force(tmppath, path) < 0) {
380 528 hiro
                FILE_OP_ERROR(tmppath, "rename");
381 528 hiro
                g_unlink(tmppath);
382 528 hiro
                g_free(path);
383 528 hiro
                g_free(tmppath);
384 528 hiro
                g_free(bakpath);
385 528 hiro
                return -1;
386 528 hiro
        }
387 528 hiro
388 528 hiro
        g_free(path);
389 528 hiro
        g_free(tmppath);
390 528 hiro
        g_free(bakpath);
391 528 hiro
        return 0;
392 528 hiro
}
393 528 hiro
394 528 hiro
gint prefs_file_close_revert(PrefFile *pfile)
395 528 hiro
{
396 528 hiro
        gchar *tmppath;
397 528 hiro
398 528 hiro
        g_return_val_if_fail(pfile != NULL, -1);
399 528 hiro
400 528 hiro
        tmppath = g_strconcat(pfile->path, ".tmp", NULL);
401 528 hiro
        fclose(pfile->fp);
402 528 hiro
        if (g_unlink(tmppath) < 0)
403 528 hiro
                FILE_OP_ERROR(tmppath, "unlink");
404 528 hiro
        g_free(tmppath);
405 528 hiro
        g_free(pfile->path);
406 528 hiro
        g_free(pfile);
407 528 hiro
408 528 hiro
        return 0;
409 528 hiro
}
410 528 hiro
411 528 hiro
void prefs_set_default(PrefParam *param)
412 528 hiro
{
413 528 hiro
        gint i;
414 528 hiro
415 528 hiro
        g_return_if_fail(param != NULL);
416 528 hiro
417 528 hiro
        for (i = 0; param[i].name != NULL; i++) {
418 528 hiro
                if (!param[i].data) continue;
419 528 hiro
420 528 hiro
                switch (param[i].type) {
421 528 hiro
                case P_STRING:
422 528 hiro
                        if (param[i].defval != NULL) {
423 528 hiro
                                if (!g_ascii_strncasecmp(param[i].defval, "ENV_", 4)) {
424 528 hiro
                                        const gchar *envstr;
425 528 hiro
                                        gchar *tmp = NULL;
426 528 hiro
427 528 hiro
                                        envstr = g_getenv(param[i].defval + 4);
428 624 hiro
#ifdef G_OS_WIN32
429 624 hiro
                                        tmp = g_strdup(envstr);
430 624 hiro
#else
431 528 hiro
                                        if (envstr) {
432 528 hiro
                                                tmp = conv_codeset_strdup
433 528 hiro
                                                        (envstr,
434 528 hiro
                                                         conv_get_locale_charset_str(),
435 528 hiro
                                                         CS_UTF_8);
436 528 hiro
                                                if (!tmp) {
437 528 hiro
                                                        g_warning("failed to convert character set.");
438 528 hiro
                                                        tmp = g_strdup(envstr);
439 528 hiro
                                                }
440 528 hiro
                                        }
441 624 hiro
#endif
442 528 hiro
                                        *((gchar **)param[i].data) = tmp;
443 528 hiro
                                } else if (param[i].defval[0] == '~')
444 528 hiro
                                        *((gchar **)param[i].data) =
445 624 hiro
#ifdef G_OS_WIN32
446 624 hiro
                                                g_strconcat(get_rc_dir(),
447 624 hiro
#else
448 528 hiro
                                                g_strconcat(get_home_dir(),
449 624 hiro
#endif
450 528 hiro
                                                            param[i].defval + 1,
451 528 hiro
                                                            NULL);
452 528 hiro
                                else if (param[i].defval[0] != '\0')
453 528 hiro
                                        *((gchar **)param[i].data) =
454 528 hiro
                                                g_strdup(param[i].defval);
455 528 hiro
                                else
456 528 hiro
                                        *((gchar **)param[i].data) = NULL;
457 528 hiro
                        } else
458 528 hiro
                                *((gchar **)param[i].data) = NULL;
459 528 hiro
                        break;
460 528 hiro
                case P_INT:
461 528 hiro
                        if (param[i].defval != NULL)
462 528 hiro
                                *((gint *)param[i].data) =
463 528 hiro
                                        (gint)atoi(param[i].defval);
464 528 hiro
                        else
465 528 hiro
                                *((gint *)param[i].data) = 0;
466 528 hiro
                        break;
467 528 hiro
                case P_BOOL:
468 528 hiro
                        if (param[i].defval != NULL) {
469 528 hiro
                                if (!g_ascii_strcasecmp(param[i].defval, "TRUE"))
470 528 hiro
                                        *((gboolean *)param[i].data) = TRUE;
471 528 hiro
                                else
472 528 hiro
                                        *((gboolean *)param[i].data) =
473 528 hiro
                                                atoi(param[i].defval) ? TRUE : FALSE;
474 528 hiro
                        } else
475 528 hiro
                                *((gboolean *)param[i].data) = FALSE;
476 528 hiro
                        break;
477 528 hiro
                case P_ENUM:
478 528 hiro
                        if (param[i].defval != NULL)
479 528 hiro
                                *((DummyEnum*)param[i].data) =
480 528 hiro
                                        (DummyEnum)atoi(param[i].defval);
481 528 hiro
                        else
482 528 hiro
                                *((DummyEnum *)param[i].data) = 0;
483 528 hiro
                        break;
484 528 hiro
                case P_USHORT:
485 528 hiro
                        if (param[i].defval != NULL)
486 528 hiro
                                *((gushort *)param[i].data) =
487 528 hiro
                                        (gushort)atoi(param[i].defval);
488 528 hiro
                        else
489 528 hiro
                                *((gushort *)param[i].data) = 0;
490 528 hiro
                        break;
491 528 hiro
                default:
492 528 hiro
                        break;
493 528 hiro
                }
494 528 hiro
        }
495 528 hiro
}
496 528 hiro
497 528 hiro
void prefs_free(PrefParam *param)
498 528 hiro
{
499 528 hiro
        gint i;
500 528 hiro
501 528 hiro
        g_return_if_fail(param != NULL);
502 528 hiro
503 528 hiro
        for (i = 0; param[i].name != NULL; i++) {
504 528 hiro
                if (!param[i].data) continue;
505 528 hiro
506 528 hiro
                switch (param[i].type) {
507 528 hiro
                case P_STRING:
508 528 hiro
                        g_free(*((gchar **)param[i].data));
509 528 hiro
                        break;
510 528 hiro
                default:
511 528 hiro
                        break;
512 528 hiro
                }
513 528 hiro
        }
514 528 hiro
}