Statistics
| Revision:

root / libsylph / prefs.c @ 1973

History | View | Annotate | Download (11 kB)

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